summaryrefslogtreecommitdiff
path: root/spec/ruby/library/stringscanner/match_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/library/stringscanner/match_spec.rb')
0 files changed, 0 insertions, 0 deletions
> -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.yml6
-rw-r--r--.github/codeql/codeql-config.yml3
-rw-r--r--.github/dependabot.yml4
-rw-r--r--.github/workflows/annocheck.yml127
-rw-r--r--.github/workflows/auto_request_review.yml4
-rw-r--r--.github/workflows/baseruby.yml65
-rw-r--r--.github/workflows/bundled_gems.yml138
-rw-r--r--.github/workflows/check_dependencies.yml70
-rw-r--r--.github/workflows/check_misc.yml117
-rw-r--r--.github/workflows/cirrus-notify.yml46
-rw-r--r--.github/workflows/codeql-analysis.yml135
-rw-r--r--.github/workflows/compilers.yml180
-rw-r--r--.github/workflows/dependabot_automerge.yml30
-rw-r--r--.github/workflows/macos.yml111
-rw-r--r--.github/workflows/mingw.yml142
-rw-r--r--.github/workflows/mjit-bindgen.yml97
-rw-r--r--.github/workflows/mjit.yml103
-rw-r--r--.github/workflows/publish.yml18
-rw-r--r--.github/workflows/rjit-bindgen.yml91
-rw-r--r--.github/workflows/rjit.yml120
-rw-r--r--.github/workflows/scorecards.yml28
-rw-r--r--.github/workflows/spec_guards.yml40
-rw-r--r--.github/workflows/ubuntu.yml137
-rw-r--r--.github/workflows/wasm.yml105
-rw-r--r--.github/workflows/windows.yml155
-rw-r--r--.github/workflows/yjit-macos.yml151
-rw-r--r--.github/workflows/yjit-ubuntu.yml183
-rw-r--r--.gitignore45
-rw-r--r--.travis.yml202
-rw-r--r--LEGAL28
-rw-r--r--NEWS.md1171
-rw-r--r--README.ja.md27
-rw-r--r--README.md20
-rw-r--r--addr2line.c825
-rw-r--r--addr2line.h4
-rw-r--r--array.c768
-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_dup.yml7
-rw-r--r--benchmark/string_rpartition.yml18
-rw-r--r--benchmark/struct_accessor.yml25
-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_method_splat_calls.yml13
-rw-r--r--benchmark/vm_send_cfunc.yml15
-rw-r--r--bignum.c26
-rwxr-xr-xbin/gem2
-rwxr-xr-xbootstraptest/runner.rb18
-rw-r--r--bootstraptest/test_eval.rb10
-rw-r--r--bootstraptest/test_fork.rb26
-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_method.rb9
-rw-r--r--bootstraptest/test_ractor.rb197
-rw-r--r--bootstraptest/test_rjit.rb58
-rw-r--r--bootstraptest/test_syntax.rb4
-rw-r--r--bootstraptest/test_thread.rb18
-rw-r--r--bootstraptest/test_yjit.rb1069
-rw-r--r--builtin.c15
-rw-r--r--builtin.h6
-rw-r--r--ccan/list/list.h6
-rw-r--r--class.c171
-rw-r--r--common.mk4237
-rw-r--r--compar.c27
-rw-r--r--compile.c2323
-rw-r--r--complex.c843
-rw-r--r--configure.ac355
-rw-r--r--constant.h2
-rw-r--r--cont.c266
-rw-r--r--coroutine/amd64/Context.S42
-rw-r--r--coroutine/arm64/Context.S67
-rw-r--r--coroutine/arm64/Context.h24
-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.in17
-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.c853
-rw-r--r--dir.rb377
-rw-r--r--dln.c80
-rw-r--r--dln.h1
-rw-r--r--dln_find.c2
-rw-r--r--dmydln.c9
-rw-r--r--doc/.document5
-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/_regexp.rdoc1276
-rw-r--r--doc/_timezones.rdoc162
-rw-r--r--doc/bsearch.rdoc2
-rw-r--r--doc/case_mapping.rdoc6
-rw-r--r--doc/character_selectors.rdoc6
-rw-r--r--doc/command_injection.rdoc4
-rw-r--r--doc/contributing/building_ruby.md122
-rw-r--r--doc/contributing/documentation_guide.md144
-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.rdoc48
-rw-r--r--doc/extension.ja.rdoc10
-rw-r--r--doc/extension.rdoc163
-rw-r--r--doc/format_specifications.rdoc58
-rw-r--r--doc/globals.rdoc491
-rw-r--r--doc/implicit_conversion.rdoc10
-rw-r--r--doc/irb/indexes.md189
-rw-r--r--doc/irb/irb.rd.ja4
-rw-r--r--doc/keywords.rdoc2
-rw-r--r--doc/maintainers.md520
-rw-r--r--doc/maintainers.rdoc424
-rw-r--r--doc/mjit/mjit.md39
-rw-r--r--doc/net-http/examples.rdoc3
-rw-r--r--doc/net-http/included_getters.rdoc3
-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.rdoc87
-rw-r--r--doc/ractor.md8
-rw-r--r--doc/rdoc/markup_reference.rb47
-rw-r--r--doc/regexp.rdoc801
-rw-r--r--doc/regexp/methods.rdoc41
-rw-r--r--doc/regexp/unicode_properties.rdoc678
-rw-r--r--doc/reline/face.md111
-rw-r--r--doc/rjit/rjit.md45
-rw-r--r--doc/standard_library.rdoc18
-rw-r--r--doc/strftime_formatting.rdoc48
-rw-r--r--doc/string/encode.rdoc47
-rw-r--r--doc/string/length.rdoc1
-rw-r--r--doc/string/new.rdoc4
-rw-r--r--doc/syntax.rdoc3
-rw-r--r--doc/syntax/assignment.rdoc6
-rw-r--r--doc/syntax/calling_methods.rdoc12
-rw-r--r--doc/syntax/comments.rdoc2
-rw-r--r--doc/syntax/control_expressions.rdoc68
-rw-r--r--doc/syntax/literals.rdoc18
-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/timezones.rdoc108
-rw-r--r--doc/transcode.rdoc52
-rw-r--r--doc/windows.md233
-rw-r--r--doc/yjit/yjit.md241
-rw-r--r--enc/Makefile.in2
-rw-r--r--enc/cesu_8.c23
-rw-r--r--enc/depend206
-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.c67
-rw-r--r--enum.c265
-rw-r--r--enumerator.c235
-rw-r--r--error.c525
-rw-r--r--eval.c79
-rw-r--r--eval_error.c33
-rw-r--r--eval_intern.h8
-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-/load/resolve_symbol_resolver/extconf.rb1
-rw-r--r--ext/-test-/load/resolve_symbol_resolver/resolve_symbol_resolver.c55
-rw-r--r--ext/-test-/load/resolve_symbol_target/extconf.rb1
-rw-r--r--ext/-test-/load/resolve_symbol_target/resolve_symbol_target.c15
-rw-r--r--ext/-test-/load/resolve_symbol_target/resolve_symbol_target.def4
-rw-r--r--ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h4
-rw-r--r--ext/-test-/load/stringify_symbols/extconf.rb1
-rw-r--r--ext/-test-/load/stringify_symbols/stringify_symbols.c29
-rw-r--r--ext/-test-/load/stringify_target/extconf.rb1
-rw-r--r--ext/-test-/load/stringify_target/stringify_target.c15
-rw-r--r--ext/-test-/load/stringify_target/stringify_target.def4
-rw-r--r--ext/-test-/load/stringify_target/stringify_target.h4
-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-/postponed_job/postponed_job.c131
-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-/string/set_len.c10
-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.c215
-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-/tracepoint/gc_hook.c4
-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.c174
-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.c35
-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.c655
-rw-r--r--ext/io/console/depend3
-rw-r--r--ext/io/console/extconf.rb13
-rw-r--r--ext/io/console/io-console.gemspec20
-rw-r--r--ext/io/nonblock/depend3
-rw-r--r--ext/io/nonblock/extconf.rb7
-rw-r--r--ext/io/nonblock/io-nonblock.gemspec2
-rw-r--r--ext/io/nonblock/nonblock.c71
-rw-r--r--ext/io/wait/depend3
-rw-r--r--ext/io/wait/extconf.rb1
-rw-r--r--ext/io/wait/io-wait.gemspec2
-rw-r--r--ext/io/wait/wait.c11
-rw-r--r--ext/json/VERSION1
-rw-r--r--ext/json/generator/depend3
-rw-r--r--ext/json/generator/generator.c145
-rw-r--r--ext/json/generator/generator.h13
-rw-r--r--ext/json/json.gemspec13
-rw-r--r--ext/json/lib/json.rb9
-rw-r--r--ext/json/lib/json/add/bigdecimal.rb45
-rw-r--r--ext/json/lib/json/add/complex.rb33
-rw-r--r--ext/json/lib/json/add/date.rb32
-rw-r--r--ext/json/lib/json/add/date_time.rb33
-rw-r--r--ext/json/lib/json/add/exception.rb30
-rw-r--r--ext/json/lib/json/add/ostruct.rb39
-rw-r--r--ext/json/lib/json/add/range.rb39
-rw-r--r--ext/json/lib/json/add/rational.rb32
-rw-r--r--ext/json/lib/json/add/regexp.rb32
-rw-r--r--ext/json/lib/json/add/set.rb31
-rw-r--r--ext/json/lib/json/add/struct.rb34
-rw-r--r--ext/json/lib/json/add/symbol.rb31
-rw-r--r--ext/json/lib/json/add/time.rb31
-rw-r--r--ext/json/lib/json/common.rb63
-rw-r--r--ext/json/lib/json/generic_object.rb8
-rw-r--r--ext/json/lib/json/version.rb2
-rw-r--r--ext/json/parser/depend3
-rw-r--r--ext/json/parser/parser.c4792
-rw-r--r--ext/json/parser/parser.rl173
-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/depend74
-rw-r--r--ext/objspace/lib/objspace.rb35
-rw-r--r--ext/objspace/object_tracing.c7
-rw-r--r--ext/objspace/objspace.c146
-rw-r--r--ext/objspace/objspace_dump.c68
-rw-r--r--ext/openssl/History.md42
-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.c76
-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/to_ruby.rb2
-rw-r--r--ext/psych/lib/psych/visitors/yaml_tree.rb17
-rw-r--r--ext/psych/psych.gemspec50
-rw-r--r--ext/pty/depend3
-rw-r--r--ext/pty/pty.c63
-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/depend564
-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/depend315
-rw-r--r--ext/socket/extconf.rb25
-rw-r--r--ext/socket/getaddrinfo.c3
-rw-r--r--ext/socket/init.c79
-rw-r--r--ext/socket/lib/socket.rb21
-rw-r--r--ext/socket/mkconstants.rb13
-rw-r--r--ext/socket/raddrinfo.c530
-rw-r--r--ext/socket/rubysocket.h5
-rw-r--r--ext/socket/socket.c5
-rw-r--r--ext/socket/unixsocket.c2
-rw-r--r--ext/stringio/depend3
-rw-r--r--ext/stringio/extconf.rb7
-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.rb1
-rw-r--r--ext/strscan/strscan.c136
-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.c11
-rw-r--r--ext/zlib/zlib.gemspec2
-rw-r--r--file.c736
-rw-r--r--gc.c3161
-rw-r--r--gc.h147
-rw-r--r--gc.rb104
-rw-r--r--gem_prelude.rb2
-rw-r--r--gems/bundled_gems31
-rw-r--r--gems/lib/core_assertions.rb1
-rw-r--r--gems/lib/rake/extensiontask.rb10
-rw-r--r--hash.c1014
-rw-r--r--id_table.c6
-rw-r--r--include/ruby/atomic.h51
-rw-r--r--include/ruby/backward/2/attributes.h24
-rw-r--r--include/ruby/debug.h171
-rw-r--r--include/ruby/fiber/scheduler.h80
-rw-r--r--include/ruby/intern.h1
-rw-r--r--include/ruby/internal/abi.h2
-rw-r--r--include/ruby/internal/attr/noexcept.h2
-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.h93
-rw-r--r--include/ruby/internal/gc.h793
-rw-r--r--include/ruby/internal/globals.h2
-rw-r--r--include/ruby/internal/has/c_attribute.h12
-rw-r--r--include/ruby/internal/intern/array.h2
-rw-r--r--include/ruby/internal/intern/bignum.h4
-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/load.h37
-rw-r--r--include/ruby/internal/intern/process.h11
-rw-r--r--include/ruby/internal/intern/re.h5
-rw-r--r--include/ruby/internal/intern/select.h2
-rw-r--r--include/ruby/internal/intern/signal.h6
-rw-r--r--include/ruby/internal/intern/struct.h30
-rw-r--r--include/ruby/internal/memory.h2
-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.h30
-rw-r--r--include/ruby/memory_view.h4
-rw-r--r--include/ruby/onigmo.h5
-rw-r--r--include/ruby/random.h2
-rw-r--r--include/ruby/re.h25
-rw-r--r--include/ruby/ruby.h125
-rw-r--r--include/ruby/st.h6
-rw-r--r--include/ruby/thread.h87
-rw-r--r--include/ruby/thread_native.h5
-rw-r--r--include/ruby/util.h13
-rw-r--r--include/ruby/version.h2
-rw-r--r--include/ruby/win32.h8
-rw-r--r--inits.c15
-rw-r--r--insns.def105
-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.h139
-rw-r--r--internal/cmdlineopt.h12
-rw-r--r--internal/compile.h3
-rw-r--r--internal/cont.h3
-rw-r--r--internal/encoding.h3
-rw-r--r--internal/error.h29
-rw-r--r--internal/eval.h1
-rw-r--r--internal/gc.h232
-rw-r--r--internal/hash.h94
-rw-r--r--internal/imemo.h4
-rw-r--r--internal/io.h99
-rw-r--r--internal/numeric.h2
-rw-r--r--internal/object.h5
-rw-r--r--internal/parse.h97
-rw-r--r--internal/proc.h3
-rw-r--r--internal/process.h15
-rw-r--r--internal/random.h1
-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.h19
-rw-r--r--internal/struct.h44
-rw-r--r--internal/symbol.h3
-rw-r--r--internal/thread.h28
-rw-r--r--internal/time.h5
-rw-r--r--internal/transcode.h3
-rw-r--r--internal/variable.h60
-rw-r--r--internal/vm.h28
-rw-r--r--io.c882
-rw-r--r--io.rb13
-rw-r--r--io_buffer.c2007
-rw-r--r--iseq.c554
-rw-r--r--iseq.h24
-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.rb242
-rw-r--r--lib/bundler.rb204
-rw-r--r--lib/bundler/build_metadata.rb2
-rw-r--r--lib/bundler/bundler.gemspec8
-rw-r--r--lib/bundler/capistrano.rb2
-rw-r--r--lib/bundler/checksum.rb254
-rw-r--r--lib/bundler/ci_detector.rb75
-rw-r--r--lib/bundler/cli.rb516
-rw-r--r--lib/bundler/cli/add.rb8
-rw-r--r--lib/bundler/cli/binstubs.rb10
-rw-r--r--lib/bundler/cli/cache.rb2
-rw-r--r--lib/bundler/cli/check.rb6
-rw-r--r--lib/bundler/cli/common.rb10
-rw-r--r--lib/bundler/cli/config.rb15
-rw-r--r--lib/bundler/cli/console.rb5
-rw-r--r--lib/bundler/cli/doctor.rb4
-rw-r--r--lib/bundler/cli/exec.rb2
-rw-r--r--lib/bundler/cli/fund.rb2
-rw-r--r--lib/bundler/cli/gem.rb86
-rw-r--r--lib/bundler/cli/info.rb15
-rw-r--r--lib/bundler/cli/init.rb4
-rw-r--r--lib/bundler/cli/install.rb30
-rw-r--r--lib/bundler/cli/issue.rb2
-rw-r--r--lib/bundler/cli/lock.rb62
-rw-r--r--lib/bundler/cli/open.rb12
-rw-r--r--lib/bundler/cli/outdated.rb48
-rw-r--r--lib/bundler/cli/platform.rb12
-rw-r--r--lib/bundler/cli/plugin.rb24
-rw-r--r--lib/bundler/cli/pristine.rb68
-rw-r--r--lib/bundler/cli/show.rb4
-rw-r--r--lib/bundler/cli/update.rb11
-rw-r--r--lib/bundler/compact_index_client.rb138
-rw-r--r--lib/bundler/compact_index_client/cache.rb115
-rw-r--r--lib/bundler/compact_index_client/cache_file.rb153
-rw-r--r--lib/bundler/compact_index_client/gem_parser.rb10
-rw-r--r--lib/bundler/compact_index_client/parser.rb84
-rw-r--r--lib/bundler/compact_index_client/updater.rb160
-rw-r--r--lib/bundler/constants.rb9
-rw-r--r--lib/bundler/current_ruby.rb28
-rw-r--r--lib/bundler/definition.rb523
-rw-r--r--lib/bundler/dependency.rb35
-rw-r--r--lib/bundler/digest.rb4
-rw-r--r--lib/bundler/dsl.rb154
-rw-r--r--lib/bundler/endpoint_specification.rb23
-rw-r--r--lib/bundler/env.rb10
-rw-r--r--lib/bundler/environment_preserver.rb32
-rw-r--r--lib/bundler/errors.rb74
-rw-r--r--lib/bundler/feature_flag.rb1
-rw-r--r--lib/bundler/fetcher.rb134
-rw-r--r--lib/bundler/fetcher/base.rb8
-rw-r--r--lib/bundler/fetcher/compact_index.rb55
-rw-r--r--lib/bundler/fetcher/dependency.rb8
-rw-r--r--lib/bundler/fetcher/downloader.rb26
-rw-r--r--lib/bundler/fetcher/gem_remote_fetcher.rb16
-rw-r--r--lib/bundler/fetcher/index.rb5
-rw-r--r--lib/bundler/force_platform.rb2
-rw-r--r--lib/bundler/friendly_errors.rb12
-rw-r--r--lib/bundler/gem_helper.rb11
-rw-r--r--lib/bundler/gem_helpers.rb25
-rw-r--r--lib/bundler/gem_version_promoter.rb82
-rw-r--r--lib/bundler/graph.rb18
-rw-r--r--lib/bundler/index.rb100
-rw-r--r--lib/bundler/injector.rb16
-rw-r--r--lib/bundler/inline.rb45
-rw-r--r--lib/bundler/installer.rb62
-rw-r--r--lib/bundler/installer/gem_installer.rb25
-rw-r--r--lib/bundler/installer/parallel_installer.rb54
-rw-r--r--lib/bundler/installer/standalone.rb24
-rw-r--r--lib/bundler/lazy_specification.rb60
-rw-r--r--lib/bundler/lockfile_generator.rb13
-rw-r--r--lib/bundler/lockfile_parser.rb177
-rw-r--r--lib/bundler/man/bundle-add.170
-rw-r--r--lib/bundler/man/bundle-add.1.ronn51
-rw-r--r--lib/bundler/man/bundle-binstubs.120
-rw-r--r--lib/bundler/man/bundle-cache.131
-rw-r--r--lib/bundler/man/bundle-cache.1.ronn4
-rw-r--r--lib/bundler/man/bundle-check.117
-rw-r--r--lib/bundler/man/bundle-check.1.ronn3
-rw-r--r--lib/bundler/man/bundle-clean.113
-rw-r--r--lib/bundler/man/bundle-config.1238
-rw-r--r--lib/bundler/man/bundle-config.1.ronn18
-rw-r--r--lib/bundler/man/bundle-console.126
-rw-r--r--lib/bundler/man/bundle-doctor.122
-rw-r--r--lib/bundler/man/bundle-exec.187
-rw-r--r--lib/bundler/man/bundle-exec.1.ronn5
-rw-r--r--lib/bundler/man/bundle-gem.168
-rw-r--r--lib/bundler/man/bundle-gem.1.ronn11
-rw-r--r--lib/bundler/man/bundle-help.110
-rw-r--r--lib/bundler/man/bundle-info.116
-rw-r--r--lib/bundler/man/bundle-info.1.ronn6
-rw-r--r--lib/bundler/man/bundle-init.117
-rw-r--r--lib/bundler/man/bundle-init.1.ronn2
-rw-r--r--lib/bundler/man/bundle-inject.125
-rw-r--r--lib/bundler/man/bundle-install.1156
-rw-r--r--lib/bundler/man/bundle-install.1.ronn5
-rw-r--r--lib/bundler/man/bundle-list.123
-rw-r--r--lib/bundler/man/bundle-lock.134
-rw-r--r--lib/bundler/man/bundle-open.134
-rw-r--r--lib/bundler/man/bundle-outdated.178
-rw-r--r--lib/bundler/man/bundle-outdated.1.ronn20
-rw-r--r--lib/bundler/man/bundle-platform.132
-rw-r--r--lib/bundler/man/bundle-plugin.171
-rw-r--r--lib/bundler/man/bundle-plugin.1.ronn20
-rw-r--r--lib/bundler/man/bundle-pristine.121
-rw-r--r--lib/bundler/man/bundle-remove.118
-rw-r--r--lib/bundler/man/bundle-show.113
-rw-r--r--lib/bundler/man/bundle-update.1155
-rw-r--r--lib/bundler/man/bundle-version.119
-rw-r--r--lib/bundler/man/bundle-viz.120
-rw-r--r--lib/bundler/man/bundle.149
-rw-r--r--lib/bundler/man/gemfile.5337
-rw-r--r--lib/bundler/man/gemfile.5.ronn26
-rw-r--r--lib/bundler/match_metadata.rb4
-rw-r--r--lib/bundler/match_platform.rb2
-rw-r--r--lib/bundler/mirror.rb6
-rw-r--r--lib/bundler/plugin.rb21
-rw-r--r--lib/bundler/plugin/api/source.rb12
-rw-r--r--lib/bundler/plugin/index.rb10
-rw-r--r--lib/bundler/plugin/installer.rb59
-rw-r--r--lib/bundler/plugin/installer/path.rb18
-rw-r--r--lib/bundler/plugin/source_list.rb8
-rw-r--r--lib/bundler/remote_specification.rb12
-rw-r--r--lib/bundler/resolver.rb243
-rw-r--r--lib/bundler/resolver/base.rb56
-rw-r--r--lib/bundler/resolver/candidate.rb22
-rw-r--r--lib/bundler/resolver/incompatibility.rb2
-rw-r--r--lib/bundler/resolver/package.rb20
-rw-r--r--lib/bundler/resolver/spec_group.rb27
-rw-r--r--lib/bundler/retry.rb4
-rw-r--r--lib/bundler/ruby_dsl.rb49
-rw-r--r--lib/bundler/ruby_version.rb23
-rw-r--r--lib/bundler/rubygems_ext.rb244
-rw-r--r--lib/bundler/rubygems_gem_installer.rb113
-rw-r--r--lib/bundler/rubygems_integration.rb147
-rw-r--r--lib/bundler/runtime.rb15
-rw-r--r--lib/bundler/safe_marshal.rb31
-rw-r--r--lib/bundler/self_manager.rb60
-rw-r--r--lib/bundler/settings.rb187
-rw-r--r--lib/bundler/setup.rb14
-rw-r--r--lib/bundler/shared_helpers.rb75
-rw-r--r--lib/bundler/source.rb4
-rw-r--r--lib/bundler/source/git.rb148
-rw-r--r--lib/bundler/source/git/git_proxy.rb167
-rw-r--r--lib/bundler/source/metadata.rb32
-rw-r--r--lib/bundler/source/path.rb32
-rw-r--r--lib/bundler/source/rubygems.rb182
-rw-r--r--lib/bundler/source/rubygems/remote.rb2
-rw-r--r--lib/bundler/source_list.rb32
-rw-r--r--lib/bundler/spec_set.rb154
-rw-r--r--lib/bundler/stub_specification.rb30
-rw-r--r--lib/bundler/templates/Executable.bundler4
-rw-r--r--lib/bundler/templates/gems.rb5
-rw-r--r--lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt106
-rw-r--r--lib/bundler/templates/newgem/Gemfile.tt2
-rw-r--r--lib/bundler/templates/newgem/README.md.tt10
-rw-r--r--lib/bundler/templates/newgem/Rakefile.tt24
-rw-r--r--lib/bundler/templates/newgem/bin/console.tt4
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt2
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt5
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/newgem.c.tt2
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt8
-rw-r--r--lib/bundler/templates/newgem/github/workflows/main.yml.tt4
-rw-r--r--lib/bundler/templates/newgem/newgem.gemspec.tt8
-rw-r--r--lib/bundler/templates/newgem/rubocop.yml.tt5
-rw-r--r--lib/bundler/templates/newgem/standard.yml.tt2
-rw-r--r--lib/bundler/ui/rg_proxy.rb2
-rw-r--r--lib/bundler/ui/shell.rb28
-rw-r--r--lib/bundler/ui/silent.rb13
-rw-r--r--lib/bundler/uri_credentials_filter.rb4
-rw-r--r--lib/bundler/uri_normalizer.rb23
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool.rb59
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb2
-rw-r--r--lib/bundler/vendor/fileutils/lib/fileutils.rb30
-rw-r--r--lib/bundler/vendor/net-http-persistent/.document1
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb166
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb7
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb34
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb2
-rw-r--r--lib/bundler/vendor/pub_grub/.document1
-rw-r--r--lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb13
-rw-r--r--lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb10
-rw-r--r--lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb9
-rw-r--r--lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb6
-rw-r--r--lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb18
-rw-r--r--lib/bundler/vendor/securerandom/.document1
-rw-r--r--lib/bundler/vendor/securerandom/lib/random/formatter.rb373
-rw-r--r--lib/bundler/vendor/securerandom/lib/securerandom.rb96
-rw-r--r--lib/bundler/vendor/thor/.document1
-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.rb47
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb29
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/html.rb45
-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/vendor/tsort/.document1
-rw-r--r--lib/bundler/vendor/tsort/lib/tsort.rb3
-rw-r--r--lib/bundler/vendor/uri/.document1
-rw-r--r--lib/bundler/vendor/uri/lib/uri/common.rb390
-rw-r--r--lib/bundler/vendor/uri/lib/uri/generic.rb1
-rw-r--r--lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb4
-rw-r--r--lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb128
-rw-r--r--lib/bundler/vendor/uri/lib/uri/version.rb2
-rw-r--r--lib/bundler/vendored_net_http.rb23
-rw-r--r--lib/bundler/vendored_persistent.rb4
-rw-r--r--lib/bundler/vendored_securerandom.rb14
-rw-r--r--lib/bundler/vendored_timeout.rb12
-rw-r--r--lib/bundler/vendored_uri.rb19
-rw-r--r--lib/bundler/version.rb2
-rw-r--r--lib/bundler/vlad.rb2
-rw-r--r--lib/bundler/yaml_serializer.rb35
-rw-r--r--lib/cgi.rb2
-rw-r--r--lib/cgi/cgi.gemspec3
-rw-r--r--lib/cgi/cookie.rb5
-rw-r--r--lib/cgi/session.rb2
-rw-r--r--lib/cgi/session/pstore.rb7
-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/error_highlight/version.rb2
-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.rb42
-rw-r--r--lib/irb.rb1865
-rw-r--r--lib/irb/cmd/backtrace.rb21
-rw-r--r--lib/irb/cmd/break.rb21
-rw-r--r--lib/irb/cmd/catch.rb21
-rw-r--r--lib/irb/cmd/chws.rb42
-rw-r--r--lib/irb/cmd/continue.rb17
-rw-r--r--lib/irb/cmd/debug.rb136
-rw-r--r--lib/irb/cmd/delete.rb17
-rw-r--r--lib/irb/cmd/edit.rb61
-rw-r--r--lib/irb/cmd/finish.rb17
-rw-r--r--lib/irb/cmd/fork.rb40
-rw-r--r--lib/irb/cmd/help.rb63
-rw-r--r--lib/irb/cmd/info.rb21
-rw-r--r--lib/irb/cmd/irb_info.rb37
-rw-r--r--lib/irb/cmd/load.rb82
-rw-r--r--lib/irb/cmd/ls.rb116
-rw-r--r--lib/irb/cmd/measure.rb48
-rw-r--r--lib/irb/cmd/next.rb17
-rw-r--r--lib/irb/cmd/nop.rb73
-rw-r--r--lib/irb/cmd/pushws.rb51
-rw-r--r--lib/irb/cmd/show_cmds.rb39
-rw-r--r--lib/irb/cmd/show_source.rb112
-rw-r--r--lib/irb/cmd/step.rb17
-rw-r--r--lib/irb/cmd/subirb.rb71
-rw-r--r--lib/irb/cmd/whereami.rb25
-rw-r--r--lib/irb/color.rb20
-rw-r--r--lib/irb/color_printer.rb7
-rw-r--r--lib/irb/command.rb23
-rw-r--r--lib/irb/command/backtrace.rb17
-rw-r--r--lib/irb/command/base.rb62
-rw-r--r--lib/irb/command/break.rb17
-rw-r--r--lib/irb/command/catch.rb17
-rw-r--r--lib/irb/command/chws.rb40
-rw-r--r--lib/irb/command/context.rb16
-rw-r--r--lib/irb/command/continue.rb17
-rw-r--r--lib/irb/command/debug.rb71
-rw-r--r--lib/irb/command/delete.rb17
-rw-r--r--lib/irb/command/disable_irb.rb19
-rw-r--r--lib/irb/command/edit.rb63
-rw-r--r--lib/irb/command/exit.rb18
-rw-r--r--lib/irb/command/finish.rb17
-rw-r--r--lib/irb/command/force_exit.rb18
-rw-r--r--lib/irb/command/help.rb83
-rw-r--r--lib/irb/command/history.rb45
-rw-r--r--lib/irb/command/info.rb17
-rw-r--r--lib/irb/command/internal_helpers.rb27
-rw-r--r--lib/irb/command/irb_info.rb33
-rw-r--r--lib/irb/command/load.rb91
-rw-r--r--lib/irb/command/ls.rb155
-rw-r--r--lib/irb/command/measure.rb49
-rw-r--r--lib/irb/command/next.rb17
-rw-r--r--lib/irb/command/pushws.rb65
-rw-r--r--lib/irb/command/show_doc.rb51
-rw-r--r--lib/irb/command/show_source.rb74
-rw-r--r--lib/irb/command/step.rb17
-rw-r--r--lib/irb/command/subirb.rb123
-rw-r--r--lib/irb/command/whereami.rb23
-rw-r--r--lib/irb/completion.rb282
-rw-r--r--lib/irb/context.rb267
-rw-r--r--lib/irb/debug.rb130
-rw-r--r--lib/irb/debug/ui.rb103
-rw-r--r--lib/irb/default_commands.rb260
-rw-r--r--lib/irb/easter-egg.rb22
-rw-r--r--lib/irb/ext/change-ws.rb20
-rw-r--r--lib/irb/ext/eval_history.rb149
-rw-r--r--lib/irb/ext/history.rb155
-rw-r--r--lib/irb/ext/loader.rb42
-rw-r--r--lib/irb/ext/multi-irb.rb16
-rw-r--r--lib/irb/ext/save-history.rb130
-rw-r--r--lib/irb/ext/tracer.rb73
-rw-r--r--lib/irb/ext/use-loader.rb20
-rw-r--r--lib/irb/ext/workspaces.rb50
-rw-r--r--lib/irb/extend-command.rb433
-rw-r--r--lib/irb/frame.rb8
-rw-r--r--lib/irb/help.rb16
-rw-r--r--lib/irb/helper_method.rb29
-rw-r--r--lib/irb/helper_method/base.rb16
-rw-r--r--lib/irb/helper_method/conf.rb11
-rw-r--r--lib/irb/history.rb87
-rw-r--r--lib/irb/init.rb193
-rw-r--r--lib/irb/input-method.rb448
-rw-r--r--lib/irb/inspector.rb28
-rw-r--r--lib/irb/irb.gemspec10
-rw-r--r--lib/irb/lc/error.rb18
-rw-r--r--lib/irb/lc/help-message8
-rw-r--r--lib/irb/lc/ja/encoding_aliases.rb13
-rw-r--r--lib/irb/lc/ja/error.rb20
-rw-r--r--lib/irb/lc/ja/help-message13
-rw-r--r--lib/irb/locale.rb64
-rw-r--r--lib/irb/magic-file.rb38
-rw-r--r--lib/irb/nesting_parser.rb237
-rw-r--r--lib/irb/notifier.rb8
-rw-r--r--lib/irb/output-method.rb16
-rw-r--r--lib/irb/pager.rb91
-rw-r--r--lib/irb/ruby-lex.rb1150
-rw-r--r--lib/irb/ruby_logo.aa43
-rw-r--r--lib/irb/source_finder.rb139
-rw-r--r--lib/irb/src_encoding.rb7
-rw-r--r--lib/irb/statement.rb80
-rw-r--r--lib/irb/version.rb12
-rw-r--r--lib/irb/workspace.rb43
-rw-r--r--lib/irb/ws-for-case-2.rb8
-rw-r--r--lib/irb/xmp.rb12
-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.rb1408
-rw-r--r--lib/net/http/backward.rb2
-rw-r--r--lib/net/http/exceptions.rb2
-rw-r--r--lib/net/http/generic_request.rb106
-rw-r--r--lib/net/http/header.rb231
-rw-r--r--lib/net/http/net-http.gemspec13
-rw-r--r--lib/net/http/proxy_delta.rb2
-rw-r--r--lib/net/http/request.rb55
-rw-r--r--lib/net/http/requests.rb32
-rw-r--r--lib/net/http/response.rb64
-rw-r--r--lib/net/http/responses.rb562
-rw-r--r--lib/net/http/status.rb13
-rw-r--r--lib/net/https.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.rb10
-rw-r--r--lib/open3.rb1268
-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.rb99
-rw-r--r--lib/prism/debug.rb200
-rw-r--r--lib/prism/desugar_compiler.rb207
-rw-r--r--lib/prism/ffi.rb341
-rw-r--r--lib/prism/lex_compat.rb892
-rw-r--r--lib/prism/node_ext.rb189
-rw-r--r--lib/prism/node_inspector.rb68
-rw-r--r--lib/prism/pack.rb224
-rw-r--r--lib/prism/parse_result.rb460
-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.gemspec119
-rw-r--r--lib/prism/ripper_compat.rb207
-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.rb134
-rw-r--r--lib/rdoc.rb12
-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.rb4
-rw-r--r--lib/rdoc/encoding.rb18
-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/pot.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.css51
-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/markdown/literals.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.rb26
-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.rb3
-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/parser.rb6
-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/table.rb13
-rw-r--r--lib/rdoc/markup/to_ansi.rb1
-rw-r--r--lib/rdoc/markup/to_html.rb10
-rw-r--r--lib/rdoc/markup/to_html_crossref.rb2
-rw-r--r--lib/rdoc/markup/to_html_snippet.rb4
-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/c.rb29
-rw-r--r--lib/rdoc/parser/changelog.rb16
-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.rb12
-rw-r--r--lib/rdoc/parser/ruby.rb11
-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.rb48
-rw-r--r--lib/rdoc/task.rb30
-rw-r--r--lib/rdoc/text.rb10
-rw-r--r--lib/rdoc/token_stream.rb3
-rw-r--r--lib/rdoc/top_level.rb4
-rw-r--r--lib/rdoc/version.rb2
-rw-r--r--lib/readline.gemspec2
-rw-r--r--lib/readline.rb2
-rw-r--r--lib/reline.rb401
-rw-r--r--lib/reline/ansi.rb350
-rw-r--r--lib/reline/config.rb178
-rw-r--r--lib/reline/face.rb199
-rw-r--r--lib/reline/general_io.rb109
-rw-r--r--lib/reline/history.rb2
-rw-r--r--lib/reline/io.rb41
-rw-r--r--lib/reline/io/ansi.rb372
-rw-r--r--lib/reline/io/dumb.rb106
-rw-r--r--lib/reline/io/windows.rb513
-rw-r--r--lib/reline/key_actor.rb1
-rw-r--r--lib/reline/key_actor/base.rb28
-rw-r--r--lib/reline/key_actor/composite.rb17
-rw-r--r--lib/reline/key_actor/emacs.rb30
-rw-r--r--lib/reline/key_actor/vi_command.rb50
-rw-r--r--lib/reline/key_actor/vi_insert.rb14
-rw-r--r--lib/reline/key_stroke.rb172
-rw-r--r--lib/reline/kill_ring.rb4
-rw-r--r--lib/reline/line_editor.rb2981
-rw-r--r--lib/reline/reline.gemspec5
-rw-r--r--lib/reline/terminfo.rb44
-rw-r--r--lib/reline/unicode.rb212
-rw-r--r--lib/reline/unicode/east_asian_width.rb2423
-rw-r--r--lib/reline/version.rb2
-rw-r--r--lib/reline/windows.rb497
-rw-r--r--lib/resolv.gemspec11
-rw-r--r--lib/resolv.rb511
-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/.document1
-rw-r--r--lib/ruby_vm/rjit/assembler.rb1140
-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.rb394
-rw-r--r--lib/ruby_vm/rjit/c_type.rb99
-rw-r--r--lib/ruby_vm/rjit/code_block.rb91
-rw-r--r--lib/ruby_vm/rjit/compiler.rb518
-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.rb5972
-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.rb191
-rw-r--r--lib/ruby_vm/rjit/type.rb221
-rw-r--r--lib/rubygems.rb171
-rw-r--r--lib/rubygems/available_set.rb11
-rw-r--r--lib/rubygems/basic_specification.rb125
-rw-r--r--lib/rubygems/bundler_version_finder.rb12
-rw-r--r--lib/rubygems/ci_detector.rb75
-rw-r--r--lib/rubygems/command.rb84
-rw-r--r--lib/rubygems/command_manager.rb26
-rw-r--r--lib/rubygems/commands/build_command.rb18
-rw-r--r--lib/rubygems/commands/cert_command.rb12
-rw-r--r--lib/rubygems/commands/check_command.rb15
-rw-r--r--lib/rubygems/commands/cleanup_command.rb41
-rw-r--r--lib/rubygems/commands/contents_command.rb34
-rw-r--r--lib/rubygems/commands/dependency_command.rb15
-rw-r--r--lib/rubygems/commands/environment_command.rb9
-rw-r--r--lib/rubygems/commands/exec_command.rb244
-rw-r--r--lib/rubygems/commands/fetch_command.rb19
-rw-r--r--lib/rubygems/commands/generate_index_command.rb114
-rw-r--r--lib/rubygems/commands/help_command.rb23
-rw-r--r--lib/rubygems/commands/info_command.rb4
-rw-r--r--lib/rubygems/commands/install_command.rb29
-rw-r--r--lib/rubygems/commands/list_command.rb5
-rw-r--r--lib/rubygems/commands/lock_command.rb3
-rw-r--r--lib/rubygems/commands/mirror_command.rb1
-rw-r--r--lib/rubygems/commands/open_command.rb5
-rw-r--r--lib/rubygems/commands/outdated_command.rb1
-rw-r--r--lib/rubygems/commands/owner_command.rb21
-rw-r--r--lib/rubygems/commands/pristine_command.rb73
-rw-r--r--lib/rubygems/commands/push_command.rb5
-rw-r--r--lib/rubygems/commands/query_command.rb10
-rw-r--r--lib/rubygems/commands/rdoc_command.rb14
-rw-r--r--lib/rubygems/commands/rebuild_command.rb264
-rw-r--r--lib/rubygems/commands/search_command.rb5
-rw-r--r--lib/rubygems/commands/server_command.rb1
-rw-r--r--lib/rubygems/commands/setup_command.rb80
-rw-r--r--lib/rubygems/commands/signin_command.rb1
-rw-r--r--lib/rubygems/commands/signout_command.rb1
-rw-r--r--lib/rubygems/commands/sources_command.rb29
-rw-r--r--lib/rubygems/commands/specification_command.rb27
-rw-r--r--lib/rubygems/commands/stale_command.rb5
-rw-r--r--lib/rubygems/commands/uninstall_command.rb49
-rw-r--r--lib/rubygems/commands/unpack_command.rb25
-rw-r--r--lib/rubygems/commands/update_command.rb56
-rw-r--r--lib/rubygems/commands/which_command.rb3
-rw-r--r--lib/rubygems/commands/yank_command.rb5
-rw-r--r--lib/rubygems/compatibility.rb11
-rw-r--r--lib/rubygems/config_file.rb125
-rw-r--r--lib/rubygems/core_ext/kernel_gem.rb6
-rw-r--r--lib/rubygems/core_ext/kernel_require.rb91
-rw-r--r--lib/rubygems/core_ext/kernel_warn.rb9
-rw-r--r--lib/rubygems/core_ext/tcpsocket_init.rb4
-rw-r--r--lib/rubygems/defaults.rb39
-rw-r--r--lib/rubygems/dependency.rb55
-rw-r--r--lib/rubygems/dependency_installer.rb82
-rw-r--r--lib/rubygems/dependency_list.rb5
-rw-r--r--lib/rubygems/deprecate.rb155
-rw-r--r--lib/rubygems/doctor.rb15
-rw-r--r--lib/rubygems/errors.rb14
-rw-r--r--lib/rubygems/exceptions.rb20
-rw-r--r--lib/rubygems/ext.rb1
-rw-r--r--lib/rubygems/ext/build_error.rb1
-rw-r--r--lib/rubygems/ext/builder.rb55
-rw-r--r--lib/rubygems/ext/cargo_builder.rb35
-rw-r--r--lib/rubygems/ext/configure_builder.rb1
-rw-r--r--lib/rubygems/ext/ext_conf_builder.rb10
-rw-r--r--lib/rubygems/ext/rake_builder.rb10
-rw-r--r--lib/rubygems/gem_runner.rb15
-rw-r--r--lib/rubygems/gemcutter_utilities.rb148
-rw-r--r--lib/rubygems/gemcutter_utilities/webauthn_listener.rb105
-rw-r--r--lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb163
-rw-r--r--lib/rubygems/gemcutter_utilities/webauthn_poller.rb80
-rw-r--r--lib/rubygems/gemspec_helpers.rb19
-rw-r--r--lib/rubygems/indexer.rb427
-rw-r--r--lib/rubygems/install_default_message.rb1
-rw-r--r--lib/rubygems/install_message.rb1
-rw-r--r--lib/rubygems/install_update_options.rb40
-rw-r--r--lib/rubygems/installer.rb197
-rw-r--r--lib/rubygems/installer_uninstaller_utils.rb2
-rw-r--r--lib/rubygems/local_remote_options.rb32
-rw-r--r--lib/rubygems/mock_gem_ui.rb85
-rw-r--r--lib/rubygems/name_tuple.rb17
-rw-r--r--lib/rubygems/optparse.rb3
-rw-r--r--lib/rubygems/optparse/.document (renamed from lib/bundler/vendor/connection_pool/.document)0
-rw-r--r--lib/rubygems/optparse/lib/optionparser.rb (renamed from lib/rubygems/vendor/optparse/lib/optionparser.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse.rb2308
-rw-r--r--lib/rubygems/optparse/lib/optparse/ac.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/ac.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/date.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/date.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/kwargs.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/kwargs.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/shellwords.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/shellwords.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/time.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/time.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/uri.rb7
-rw-r--r--lib/rubygems/optparse/lib/optparse/version.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/version.rb)0
-rw-r--r--lib/rubygems/package.rb116
-rw-r--r--lib/rubygems/package/digest_io.rb3
-rw-r--r--lib/rubygems/package/file_source.rb1
-rw-r--r--lib/rubygems/package/io_source.rb1
-rw-r--r--lib/rubygems/package/old.rb5
-rw-r--r--lib/rubygems/package/source.rb1
-rw-r--r--lib/rubygems/package/tar_header.rb107
-rw-r--r--lib/rubygems/package/tar_reader.rb53
-rw-r--r--lib/rubygems/package/tar_reader/entry.rb125
-rw-r--r--lib/rubygems/package/tar_writer.rb41
-rw-r--r--lib/rubygems/package_task.rb5
-rw-r--r--lib/rubygems/path_support.rb22
-rw-r--r--lib/rubygems/platform.rb127
-rw-r--r--lib/rubygems/psych_tree.rb1
-rw-r--r--lib/rubygems/query_utils.rb28
-rw-r--r--lib/rubygems/rdoc.rb1
-rw-r--r--lib/rubygems/remote_fetcher.rb52
-rw-r--r--lib/rubygems/request.rb54
-rw-r--r--lib/rubygems/request/connection_pools.rb6
-rw-r--r--lib/rubygems/request/http_pool.rb1
-rw-r--r--lib/rubygems/request/https_pool.rb1
-rw-r--r--lib/rubygems/request_set.rb20
-rw-r--r--lib/rubygems/request_set/gem_dependency_api.rb247
-rw-r--r--lib/rubygems/request_set/lockfile.rb18
-rw-r--r--lib/rubygems/request_set/lockfile/parser.rb21
-rw-r--r--lib/rubygems/request_set/lockfile/tokenizer.rb34
-rw-r--r--lib/rubygems/requirement.rb24
-rw-r--r--lib/rubygems/resolver.rb28
-rw-r--r--lib/rubygems/resolver/activation_request.rb13
-rw-r--r--lib/rubygems/resolver/api_set.rb25
-rw-r--r--lib/rubygems/resolver/api_set/gem_parser.rb10
-rw-r--r--lib/rubygems/resolver/api_specification.rb3
-rw-r--r--lib/rubygems/resolver/best_set.rb29
-rw-r--r--lib/rubygems/resolver/composed_set.rb3
-rw-r--r--lib/rubygems/resolver/conflict.rb17
-rw-r--r--lib/rubygems/resolver/current_set.rb1
-rw-r--r--lib/rubygems/resolver/dependency_request.rb1
-rw-r--r--lib/rubygems/resolver/git_set.rb1
-rw-r--r--lib/rubygems/resolver/git_specification.rb1
-rw-r--r--lib/rubygems/resolver/index_set.rb9
-rw-r--r--lib/rubygems/resolver/index_specification.rb5
-rw-r--r--lib/rubygems/resolver/installed_specification.rb3
-rw-r--r--lib/rubygems/resolver/installer_set.rb16
-rw-r--r--lib/rubygems/resolver/local_specification.rb3
-rw-r--r--lib/rubygems/resolver/lock_set.rb3
-rw-r--r--lib/rubygems/resolver/lock_specification.rb1
-rw-r--r--lib/rubygems/resolver/molinillo.rb2
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo.rb11
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb57
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb88
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb255
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb36
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb66
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb62
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb63
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb61
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb126
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb46
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb36
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb164
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb149
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb6
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb112
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb67
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb839
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb46
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/state.rb58
-rw-r--r--lib/rubygems/resolver/requirement_list.rb1
-rw-r--r--lib/rubygems/resolver/set.rb1
-rw-r--r--lib/rubygems/resolver/source_set.rb2
-rw-r--r--lib/rubygems/resolver/spec_specification.rb8
-rw-r--r--lib/rubygems/resolver/specification.rb1
-rw-r--r--lib/rubygems/resolver/stats.rb3
-rw-r--r--lib/rubygems/resolver/vendor_set.rb1
-rw-r--r--lib/rubygems/resolver/vendor_specification.rb1
-rw-r--r--lib/rubygems/s3_uri_signer.rb24
-rw-r--r--lib/rubygems/safe_marshal.rb74
-rw-r--r--lib/rubygems/safe_marshal/elements.rb146
-rw-r--r--lib/rubygems/safe_marshal/reader.rb308
-rw-r--r--lib/rubygems/safe_marshal/visitors/stream_printer.rb31
-rw-r--r--lib/rubygems/safe_marshal/visitors/to_ruby.rb415
-rw-r--r--lib/rubygems/safe_marshal/visitors/visitor.rb74
-rw-r--r--lib/rubygems/safe_yaml.rb40
-rw-r--r--lib/rubygems/security.rb37
-rw-r--r--lib/rubygems/security/policies.rb75
-rw-r--r--lib/rubygems/security/policy.rb19
-rw-r--r--lib/rubygems/security/signer.rb15
-rw-r--r--lib/rubygems/security/trust_dir.rb21
-rw-r--r--lib/rubygems/security_option.rb3
-rw-r--r--lib/rubygems/shellwords.rb3
-rw-r--r--lib/rubygems/source.rb50
-rw-r--r--lib/rubygems/source/git.rb22
-rw-r--r--lib/rubygems/source/installed.rb7
-rw-r--r--lib/rubygems/source/local.rb96
-rw-r--r--lib/rubygems/source/lock.rb5
-rw-r--r--lib/rubygems/source/specific_file.rb10
-rw-r--r--lib/rubygems/source/vendor.rb3
-rw-r--r--lib/rubygems/source_list.rb16
-rw-r--r--lib/rubygems/spec_fetcher.rb102
-rw-r--r--lib/rubygems/specification.rb571
-rw-r--r--lib/rubygems/specification_policy.rb192
-rw-r--r--lib/rubygems/specification_record.rb212
-rw-r--r--lib/rubygems/stub_specification.rb84
-rw-r--r--lib/rubygems/text.rb5
-rw-r--r--lib/rubygems/tsort.rb3
-rw-r--r--lib/rubygems/tsort/.document (renamed from lib/bundler/vendor/fileutils/.document)0
-rw-r--r--lib/rubygems/tsort/lib/tsort.rb452
-rw-r--r--lib/rubygems/uninstaller.rb84
-rw-r--r--lib/rubygems/update_suggestion.rb25
-rw-r--r--lib/rubygems/uri.rb12
-rw-r--r--lib/rubygems/uri_formatter.rb2
-rw-r--r--lib/rubygems/user_interaction.rb50
-rw-r--r--lib/rubygems/util.rb15
-rw-r--r--lib/rubygems/util/licenses.rb336
-rw-r--r--lib/rubygems/util/list.rb5
-rw-r--r--lib/rubygems/validator.rb21
-rw-r--r--lib/rubygems/vendor/molinillo/.document1
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo.rb11
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb57
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb88
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph.rb255
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/action.rb36
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb66
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb62
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb63
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb61
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/log.rb126
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb46
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb36
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb164
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/errors.rb149
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/gem_metadata.rb6
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/modules/specification_provider.rb112
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/modules/ui.rb67
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/resolution.rb839
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/resolver.rb46
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/state.rb58
-rw-r--r--lib/rubygems/vendor/net-http/.document1
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http.rb2496
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/backward.rb40
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb34
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb414
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/header.rb981
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/proxy_delta.rb17
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/request.rb88
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/requests.rb425
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/response.rb738
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/responses.rb1174
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/status.rb84
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/https.rb23
-rw-r--r--lib/rubygems/vendor/net-protocol/.document1
-rw-r--r--lib/rubygems/vendor/net-protocol/lib/net/protocol.rb544
-rw-r--r--lib/rubygems/vendor/optparse/.document1
-rw-r--r--lib/rubygems/vendor/optparse/lib/optparse.rb2330
-rw-r--r--lib/rubygems/vendor/optparse/lib/optparse/uri.rb7
-rw-r--r--lib/rubygems/vendor/resolv/.document1
-rw-r--r--lib/rubygems/vendor/resolv/lib/resolv.rb3442
-rw-r--r--lib/rubygems/vendor/securerandom/.document1
-rw-r--r--lib/rubygems/vendor/securerandom/lib/random/formatter.rb373
-rw-r--r--lib/rubygems/vendor/securerandom/lib/securerandom.rb96
-rw-r--r--lib/rubygems/vendor/timeout/.document1
-rw-r--r--lib/rubygems/vendor/timeout/lib/timeout.rb199
-rw-r--r--lib/rubygems/vendor/tsort/.document1
-rw-r--r--lib/rubygems/vendor/tsort/lib/tsort.rb455
-rw-r--r--lib/rubygems/vendor/uri/.document1
-rw-r--r--lib/rubygems/vendor/uri/lib/uri.rb104
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/common.rb855
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/file.rb100
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/ftp.rb267
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/generic.rb1588
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/http.rb125
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/https.rb23
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/ldap.rb261
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/ldaps.rb22
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/mailto.rb293
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb539
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/rfc3986_parser.rb183
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/version.rb6
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/ws.rb83
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/wss.rb23
-rw-r--r--lib/rubygems/vendored_molinillo.rb3
-rw-r--r--lib/rubygems/vendored_net_http.rb5
-rw-r--r--lib/rubygems/vendored_optparse.rb3
-rw-r--r--lib/rubygems/vendored_securerandom.rb4
-rw-r--r--lib/rubygems/vendored_timeout.rb5
-rw-r--r--lib/rubygems/vendored_tsort.rb3
-rw-r--r--lib/rubygems/version.rb73
-rw-r--r--lib/rubygems/version_option.rb8
-rw-r--r--lib/rubygems/yaml_serializer.rb98
-rw-r--r--lib/securerandom.gemspec11
-rw-r--r--lib/securerandom.rb25
-rw-r--r--lib/set.rb66
-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/api.rb53
-rw-r--r--lib/syntax_suggest/around_block_scan.rb290
-rw-r--r--lib/syntax_suggest/block_expand.rb113
-rw-r--r--lib/syntax_suggest/capture/before_after_keyword_ends.rb85
-rw-r--r--lib/syntax_suggest/capture/falling_indent_lines.rb71
-rw-r--r--lib/syntax_suggest/capture_code_context.rb26
-rw-r--r--lib/syntax_suggest/clean_document.rb20
-rw-r--r--lib/syntax_suggest/code_block.rb2
-rw-r--r--lib/syntax_suggest/code_frontier.rb2
-rw-r--r--lib/syntax_suggest/code_line.rb25
-rw-r--r--lib/syntax_suggest/code_search.rb4
-rw-r--r--lib/syntax_suggest/core_ext.rb8
-rw-r--r--lib/syntax_suggest/display_invalid_blocks.rb2
-rw-r--r--lib/syntax_suggest/explain_syntax.rb22
-rw-r--r--lib/syntax_suggest/lex_all.rb39
-rw-r--r--lib/syntax_suggest/lex_value.rb2
-rw-r--r--lib/syntax_suggest/parse_blocks_from_indent_line.rb6
-rw-r--r--lib/syntax_suggest/pathname_from_message.rb2
-rw-r--r--lib/syntax_suggest/ripper_errors.rb5
-rw-r--r--lib/syntax_suggest/scan_history.rb134
-rw-r--r--lib/syntax_suggest/syntax_suggest.gemspec4
-rw-r--r--lib/syntax_suggest/version.rb2
-rw-r--r--lib/tempfile.gemspec13
-rw-r--r--lib/tempfile.rb78
-rw-r--r--lib/time.gemspec13
-rw-r--r--lib/time.rb7
-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/rfc2396_parser.rb4
-rw-r--r--lib/uri/rfc3986_parser.rb128
-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/bundle27
-rwxr-xr-xlibexec/irb2
-rwxr-xr-xlibexec/racc320
-rwxr-xr-xlibexec/syntax_suggest2
-rw-r--r--load.c242
-rw-r--r--main.c9
-rw-r--r--man/irb.17
-rw-r--r--man/ruby.178
-rw-r--r--marshal.c90
-rw-r--r--math.c82
-rw-r--r--method.h16
-rw-r--r--mini_builtin.c23
-rw-r--r--miniinit.c7
-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/call_fuzzer.rb372
-rwxr-xr-xmisc/call_fuzzer.sh13
-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--missing/setproctitle.c1
-rw-r--r--mjit.c1988
-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.c276
-rw-r--r--numeric.rb359
-rw-r--r--object.c501
-rw-r--r--pack.c8
-rw-r--r--parse.y18806
-rw-r--r--parser_bits.h564
-rw-r--r--parser_node.h32
-rw-r--r--parser_st.c164
-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.yml2704
-rw-r--r--prism/defines.h94
-rw-r--r--prism/diagnostic.c355
-rw-r--r--prism/diagnostic.h297
-rw-r--r--prism/encoding.c5137
-rw-r--r--prism/encoding.h248
-rw-r--r--prism/extension.c1055
-rw-r--r--prism/extension.h18
-rw-r--r--prism/node.h57
-rw-r--r--prism/options.c189
-rw-r--r--prism/options.h204
-rw-r--r--prism/pack.c493
-rw-r--r--prism/pack.h152
-rw-r--r--prism/parser.h716
-rw-r--r--prism/prettyprint.h26
-rw-r--r--prism/prism.c17487
-rw-r--r--prism/prism.h272
-rw-r--r--prism/regexp.c638
-rw-r--r--prism/regexp.h33
-rw-r--r--prism/templates/ext/prism/api_node.c.erb221
-rw-r--r--prism/templates/include/prism/ast.h.erb206
-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/dot_visitor.rb.erb186
-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.erb254
-rw-r--r--prism/templates/lib/prism/serialize.rb.erb310
-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.erb189
-rw-r--r--prism/templates/src/serialize.c.erb380
-rw-r--r--prism/templates/src/token_type.c.erb20
-rwxr-xr-xprism/templates/template.rb472
-rw-r--r--prism/util/pm_buffer.c179
-rw-r--r--prism/util/pm_buffer.h146
-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.c6532
-rw-r--r--prism_compile.h29
-rw-r--r--prism_init.c9
-rw-r--r--probes_helper.h2
-rw-r--r--proc.c397
-rw-r--r--process.c3058
-rw-r--r--ractor.c2042
-rw-r--r--ractor.rb255
-rw-r--r--ractor_core.h95
-rw-r--r--random.c6
-rw-r--r--range.c444
-rw-r--r--rational.c21
-rw-r--r--re.c598
-rw-r--r--regcomp.c118
-rw-r--r--regenc.c2
-rw-r--r--regexec.c1158
-rw-r--r--regint.h74
-rw-r--r--regparse.c181
-rw-r--r--regparse.h3
-rw-r--r--rjit.c501
-rw-r--r--rjit.h101
-rw-r--r--rjit.rb41
-rw-r--r--rjit_c.c542
-rw-r--r--rjit_c.h164
-rw-r--r--rjit_c.rb1695
-rw-r--r--ruby-runner.c35
-rw-r--r--ruby.c1114
-rw-r--r--ruby_parser.c913
-rw-r--r--rubyparser.h1405
-rw-r--r--sample/all-ruby-quine.rb24
-rw-r--r--sample/dir.rb11
-rw-r--r--scheduler.c128
-rw-r--r--shape.c949
-rw-r--r--shape.h147
-rw-r--r--signal.c178
-rw-r--r--spec/README.md8
-rw-r--r--spec/bundler/bundler/bundler_spec.rb86
-rw-r--r--spec/bundler/bundler/ci_detector_spec.rb21
-rw-r--r--spec/bundler/bundler/cli_spec.rb52
-rw-r--r--spec/bundler/bundler/compact_index_client/parser_spec.rb237
-rw-r--r--spec/bundler/bundler/compact_index_client/updater_spec.rb205
-rw-r--r--spec/bundler/bundler/definition_spec.rb117
-rw-r--r--spec/bundler/bundler/dependency_spec.rb212
-rw-r--r--spec/bundler/bundler/digest_spec.rb6
-rw-r--r--spec/bundler/bundler/dsl_spec.rb119
-rw-r--r--spec/bundler/bundler/endpoint_specification_spec.rb8
-rw-r--r--spec/bundler/bundler/env_spec.rb46
-rw-r--r--spec/bundler/bundler/environment_preserver_spec.rb16
-rw-r--r--spec/bundler/bundler/fetcher/base_spec.rb11
-rw-r--r--spec/bundler/bundler/fetcher/compact_index_spec.rb18
-rw-r--r--spec/bundler/bundler/fetcher/dependency_spec.rb41
-rw-r--r--spec/bundler/bundler/fetcher/downloader_spec.rb70
-rw-r--r--spec/bundler/bundler/fetcher/index_spec.rb30
-rw-r--r--spec/bundler/bundler/fetcher_spec.rb126
-rw-r--r--spec/bundler/bundler/friendly_errors_spec.rb10
-rw-r--r--spec/bundler/bundler/gem_helper_spec.rb42
-rw-r--r--spec/bundler/bundler/gem_version_promoter_spec.rb235
-rw-r--r--spec/bundler/bundler/installer/gem_installer_spec.rb13
-rw-r--r--spec/bundler/bundler/installer/parallel_installer_spec.rb46
-rw-r--r--spec/bundler/bundler/installer/spec_installation_spec.rb18
-rw-r--r--spec/bundler/bundler/lockfile_parser_spec.rb78
-rw-r--r--spec/bundler/bundler/mirror_spec.rb16
-rw-r--r--spec/bundler/bundler/plugin/api/source_spec.rb4
-rw-r--r--spec/bundler/bundler/plugin/dsl_spec.rb6
-rw-r--r--spec/bundler/bundler/plugin/index_spec.rb2
-rw-r--r--spec/bundler/bundler/plugin/installer_spec.rb21
-rw-r--r--spec/bundler/bundler/plugin_spec.rb14
-rw-r--r--spec/bundler/bundler/remote_specification_spec.rb12
-rw-r--r--spec/bundler/bundler/resolver/candidate_spec.rb19
-rw-r--r--spec/bundler/bundler/retry_spec.rb2
-rw-r--r--spec/bundler/bundler/ruby_dsl_spec.rb117
-rw-r--r--spec/bundler/bundler/ruby_version_spec.rb10
-rw-r--r--spec/bundler/bundler/rubygems_integration_spec.rb40
-rw-r--r--spec/bundler/bundler/settings/validator_spec.rb6
-rw-r--r--spec/bundler/bundler/settings_spec.rb43
-rw-r--r--spec/bundler/bundler/shared_helpers_spec.rb79
-rw-r--r--spec/bundler/bundler/source/git/git_proxy_spec.rb122
-rw-r--r--spec/bundler/bundler/source/git_spec.rb4
-rw-r--r--spec/bundler/bundler/source/rubygems/remote_spec.rb20
-rw-r--r--spec/bundler/bundler/source_list_spec.rb6
-rw-r--r--spec/bundler/bundler/source_spec.rb20
-rw-r--r--spec/bundler/bundler/spec_set_spec.rb18
-rw-r--r--spec/bundler/bundler/specifications/foo.gemspec13
-rw-r--r--spec/bundler/bundler/stub_specification_spec.rb31
-rw-r--r--spec/bundler/bundler/ui/shell_spec.rb26
-rw-r--r--spec/bundler/bundler/uri_credentials_filter_spec.rb10
-rw-r--r--spec/bundler/bundler/yaml_serializer_spec.rb57
-rw-r--r--spec/bundler/cache/cache_path_spec.rb12
-rw-r--r--spec/bundler/cache/gems_spec.rb317
-rw-r--r--spec/bundler/cache/git_spec.rb256
-rw-r--r--spec/bundler/cache/path_spec.rb34
-rw-r--r--spec/bundler/cache/platform_spec.rb18
-rw-r--r--spec/bundler/commands/add_spec.rb144
-rw-r--r--spec/bundler/commands/binstubs_spec.rb278
-rw-r--r--spec/bundler/commands/cache_spec.rb225
-rw-r--r--spec/bundler/commands/check_spec.rb231
-rw-r--r--spec/bundler/commands/clean_spec.rb266
-rw-r--r--spec/bundler/commands/config_spec.rb82
-rw-r--r--spec/bundler/commands/console_spec.rb22
-rw-r--r--spec/bundler/commands/doctor_spec.rb17
-rw-r--r--spec/bundler/commands/exec_spec.rb377
-rw-r--r--spec/bundler/commands/fund_spec.rb50
-rw-r--r--spec/bundler/commands/help_spec.rb9
-rw-r--r--spec/bundler/commands/info_spec.rb48
-rw-r--r--spec/bundler/commands/init_spec.rb53
-rw-r--r--spec/bundler/commands/inject_spec.rb60
-rw-r--r--spec/bundler/commands/install_spec.rb941
-rw-r--r--spec/bundler/commands/issue_spec.rb2
-rw-r--r--spec/bundler/commands/licenses_spec.rb4
-rw-r--r--spec/bundler/commands/list_spec.rb58
-rw-r--r--spec/bundler/commands/lock_spec.rb1364
-rw-r--r--spec/bundler/commands/newgem_spec.rb395
-rw-r--r--spec/bundler/commands/open_spec.rb63
-rw-r--r--spec/bundler/commands/outdated_spec.rb311
-rw-r--r--spec/bundler/commands/platform_spec.rb508
-rw-r--r--spec/bundler/commands/post_bundle_message_spec.rb36
-rw-r--r--spec/bundler/commands/pristine_spec.rb22
-rw-r--r--spec/bundler/commands/remove_spec.rb342
-rw-r--r--spec/bundler/commands/show_spec.rb36
-rw-r--r--spec/bundler/commands/update_spec.rb888
-rw-r--r--spec/bundler/commands/version_spec.rb16
-rw-r--r--spec/bundler/commands/viz_spec.rb76
-rw-r--r--spec/bundler/install/allow_offline_install_spec.rb42
-rw-r--r--spec/bundler/install/binstubs_spec.rb20
-rw-r--r--spec/bundler/install/bundler_spec.rb68
-rw-r--r--spec/bundler/install/deploy_spec.rb411
-rw-r--r--spec/bundler/install/failure_spec.rb8
-rw-r--r--spec/bundler/install/gemfile/eval_gemfile_spec.rb40
-rw-r--r--spec/bundler/install/gemfile/force_ruby_platform_spec.rb86
-rw-r--r--spec/bundler/install/gemfile/gemspec_spec.rb323
-rw-r--r--spec/bundler/install/gemfile/git_spec.rb580
-rw-r--r--spec/bundler/install/gemfile/groups_spec.rb106
-rw-r--r--spec/bundler/install/gemfile/install_if_spec.rb23
-rw-r--r--spec/bundler/install/gemfile/lockfile_spec.rb13
-rw-r--r--spec/bundler/install/gemfile/path_spec.rb406
-rw-r--r--spec/bundler/install/gemfile/platform_spec.rb471
-rw-r--r--spec/bundler/install/gemfile/ruby_spec.rb94
-rw-r--r--spec/bundler/install/gemfile/sources_spec.rb944
-rw-r--r--spec/bundler/install/gemfile/specific_platform_spec.rb994
-rw-r--r--spec/bundler/install/gemfile_spec.rb69
-rw-r--r--spec/bundler/install/gems/compact_index_spec.rb584
-rw-r--r--spec/bundler/install/gems/dependency_api_fallback_spec.rb53
-rw-r--r--spec/bundler/install/gems/dependency_api_spec.rb296
-rw-r--r--spec/bundler/install/gems/env_spec.rb36
-rw-r--r--spec/bundler/install/gems/flex_spec.rb207
-rw-r--r--spec/bundler/install/gems/fund_spec.rb28
-rw-r--r--spec/bundler/install/gems/mirror_spec.rb22
-rw-r--r--spec/bundler/install/gems/native_extensions_spec.rb18
-rw-r--r--spec/bundler/install/gems/post_install_spec.rb44
-rw-r--r--spec/bundler/install/gems/resolving_spec.rb289
-rw-r--r--spec/bundler/install/gems/standalone_spec.rb199
-rw-r--r--spec/bundler/install/gems/win32_spec.rb10
-rw-r--r--spec/bundler/install/gemspecs_spec.rb76
-rw-r--r--spec/bundler/install/git_spec.rb186
-rw-r--r--spec/bundler/install/global_cache_spec.rb158
-rw-r--r--spec/bundler/install/path_spec.rb90
-rw-r--r--spec/bundler/install/prereleases_spec.rb16
-rw-r--r--spec/bundler/install/process_lock_spec.rb8
-rw-r--r--spec/bundler/install/redownload_spec.rb22
-rw-r--r--spec/bundler/install/security_policy_spec.rb20
-rw-r--r--spec/bundler/install/yanked_spec.rb77
-rw-r--r--spec/bundler/lock/git_spec.rb43
-rw-r--r--spec/bundler/lock/lockfile_spec.rb1093
-rw-r--r--spec/bundler/other/cli_dispatch_spec.rb6
-rw-r--r--spec/bundler/other/ext_spec.rb28
-rw-r--r--spec/bundler/other/major_deprecation_spec.rb286
-rw-r--r--spec/bundler/plugins/command_spec.rb10
-rw-r--r--spec/bundler/plugins/hook_spec.rb34
-rw-r--r--spec/bundler/plugins/install_spec.rb148
-rw-r--r--spec/bundler/plugins/list_spec.rb4
-rw-r--r--spec/bundler/plugins/source/example_spec.rb40
-rw-r--r--spec/bundler/plugins/source_spec.rb16
-rw-r--r--spec/bundler/plugins/uninstall_spec.rb29
-rw-r--r--spec/bundler/quality_spec.rb33
-rw-r--r--spec/bundler/realworld/dependency_api_spec.rb46
-rw-r--r--spec/bundler/realworld/double_check_spec.rb6
-rw-r--r--spec/bundler/realworld/edgecases_spec.rb162
-rw-r--r--spec/bundler/realworld/ffi_spec.rb2
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile4
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile.lock6
-rw-r--r--spec/bundler/realworld/gemfile_source_header_spec.rb20
-rw-r--r--spec/bundler/realworld/git_spec.rb2
-rw-r--r--spec/bundler/realworld/mirror_probe_spec.rb24
-rw-r--r--spec/bundler/realworld/parallel_spec.rb8
-rw-r--r--spec/bundler/realworld/slow_perf_spec.rb117
-rw-r--r--spec/bundler/resolver/basic_spec.rb88
-rw-r--r--spec/bundler/resolver/platform_spec.rb2
-rw-r--r--spec/bundler/runtime/env_helpers_spec.rb307
-rw-r--r--spec/bundler/runtime/executable_spec.rb90
-rw-r--r--spec/bundler/runtime/gem_tasks_spec.rb77
-rw-r--r--spec/bundler/runtime/inline_spec.rb341
-rw-r--r--spec/bundler/runtime/load_spec.rb28
-rw-r--r--spec/bundler/runtime/platform_spec.rb146
-rw-r--r--spec/bundler/runtime/require_spec.rb80
-rw-r--r--spec/bundler/runtime/requiring_spec.rb15
-rw-r--r--spec/bundler/runtime/self_management_spec.rb121
-rw-r--r--spec/bundler/runtime/setup_spec.rb562
-rw-r--r--spec/bundler/runtime/with_unbundled_env_spec.rb302
-rw-r--r--spec/bundler/spec_helper.rb15
-rw-r--r--spec/bundler/support/activate.rb9
-rw-r--r--spec/bundler/support/api_request_limit_hax.rb16
-rw-r--r--spec/bundler/support/artifice/compact_index_checksum_mismatch.rb4
-rw-r--r--spec/bundler/support/artifice/compact_index_concurrent_download.rb7
-rw-r--r--spec/bundler/support/artifice/compact_index_etag_match.rb16
-rw-r--r--spec/bundler/support/artifice/compact_index_host_redirect.rb2
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update.rb2
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update_bad_digest.rb40
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update_no_digest_not_incremental.rb42
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb40
-rw-r--r--spec/bundler/support/artifice/compact_index_range_ignored.rb40
-rw-r--r--spec/bundler/support/artifice/compact_index_strict_basic_authentication.rb2
-rw-r--r--spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb3
-rw-r--r--spec/bundler/support/artifice/endpoint_500.rb2
-rw-r--r--spec/bundler/support/artifice/endpoint_host_redirect.rb2
-rw-r--r--spec/bundler/support/artifice/endpoint_mirror_source.rb2
-rw-r--r--spec/bundler/support/artifice/endpoint_strict_basic_authentication.rb2
-rw-r--r--spec/bundler/support/artifice/fail.rb14
-rw-r--r--spec/bundler/support/artifice/helpers/artifice.rb6
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index.rb34
-rw-r--r--spec/bundler/support/artifice/helpers/endpoint.rb12
-rw-r--r--spec/bundler/support/artifice/helpers/rack_request.rb24
-rw-r--r--spec/bundler/support/artifice/vcr.rb16
-rw-r--r--spec/bundler/support/artifice/windows.rb2
-rw-r--r--spec/bundler/support/build_metadata.rb14
-rw-r--r--spec/bundler/support/builders.rb205
-rw-r--r--spec/bundler/support/bundle.rb7
-rw-r--r--spec/bundler/support/checksums.rb126
-rw-r--r--spec/bundler/support/command_execution.rb48
-rw-r--r--spec/bundler/support/env.rb9
-rw-r--r--spec/bundler/support/filters.rb24
-rw-r--r--spec/bundler/support/hax.rb14
-rw-r--r--spec/bundler/support/helpers.rb336
-rw-r--r--spec/bundler/support/indexes.rb30
-rw-r--r--spec/bundler/support/matchers.rb16
-rw-r--r--spec/bundler/support/options.rb15
-rw-r--r--spec/bundler/support/path.rb78
-rw-r--r--spec/bundler/support/platforms.rb21
-rw-r--r--spec/bundler/support/rubygems_ext.rb34
-rw-r--r--spec/bundler/support/rubygems_version_manager.rb38
-rw-r--r--spec/bundler/support/subprocess.rb108
-rw-r--r--spec/bundler/support/vendored_net_http.rb23
-rw-r--r--spec/bundler/update/gemfile_spec.rb24
-rw-r--r--spec/bundler/update/gems/fund_spec.rb6
-rw-r--r--spec/bundler/update/gems/post_install_spec.rb24
-rw-r--r--spec/bundler/update/git_spec.rb143
-rw-r--r--spec/bundler/update/path_spec.rb6
-rw-r--r--spec/bundler/update/redownload_spec.rb26
-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.rb78
-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.rb3
-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.rb14
-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/keep_if_spec.rb1
-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.rb16
-rw-r--r--spec/ruby/core/array/pack/shared/basic.rb40
-rw-r--r--spec/ruby/core/array/pack/shared/float.rb74
-rw-r--r--spec/ruby/core/array/pack/shared/integer.rb108
-rw-r--r--spec/ruby/core/array/pack/shared/numeric_basic.rb10
-rw-r--r--spec/ruby/core/array/pack/shared/unicode.rb16
-rw-r--r--spec/ruby/core/array/pack/w_spec.rb16
-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/rassoc_spec.rb14
-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/shared/unshift.rb18
-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/array/values_at_spec.rb1
-rw-r--r--spec/ruby/core/array/zip_spec.rb6
-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/clone_spec.rb6
-rw-r--r--spec/ruby/core/binding/dup_spec.rb6
-rw-r--r--spec/ruby/core/binding/eval_spec.rb99
-rw-r--r--spec/ruby/core/binding/shared/clone.rb22
-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/class/subclasses_spec.rb22
-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.rb54
-rw-r--r--spec/ruby/core/dir/mkdir_spec.rb18
-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/enumerable/zip_spec.rb5
-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.rb92
-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.rb56
-rw-r--r--spec/ruby/core/fiber/resume_spec.rb15
-rw-r--r--spec/ruby/core/fiber/storage_spec.rb99
-rw-r--r--spec/ruby/core/file/absolute_path_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/new_spec.rb65
-rw-r--r--spec/ruby/core/file/open_spec.rb17
-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.rb8
-rw-r--r--spec/ruby/core/float/comparison_spec.rb35
-rw-r--r--spec/ruby/core/float/divmod_spec.rb2
-rw-r--r--spec/ruby/core/float/gt_spec.rb21
-rw-r--r--spec/ruby/core/float/gte_spec.rb21
-rw-r--r--spec/ruby/core/float/lt_spec.rb21
-rw-r--r--spec/ruby/core/float/lte_spec.rb21
-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/float/shared/equal.rb21
-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/hash_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.rb75
-rw-r--r--spec/ruby/core/io/initialize_spec.rb11
-rw-r--r--spec/ruby/core/io/lineno_spec.rb9
-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.rb16
-rw-r--r--spec/ruby/core/io/readlines_spec.rb43
-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.rb24
-rw-r--r--spec/ruby/core/io/shared/new.rb50
-rw-r--r--spec/ruby/core/io/shared/pos.rb8
-rw-r--r--spec/ruby/core/io/shared/readlines.rb24
-rw-r--r--spec/ruby/core/io/shared/write.rb65
-rw-r--r--spec/ruby/core/io/sysseek_spec.rb2
-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.rb38
-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.rb69
-rw-r--r--spec/ruby/core/kernel/shared/require.rb93
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb4
-rw-r--r--spec/ruby/core/kernel/singleton_class_spec.rb51
-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.rb265
-rw-r--r--spec/ruby/core/marshal/fixtures/classes.rb4
-rw-r--r--spec/ruby/core/marshal/fixtures/marshal_data.rb96
-rw-r--r--spec/ruby/core/marshal/shared/load.rb300
-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.rb71
-rw-r--r--spec/ruby/core/math/cos_spec.rb26
-rw-r--r--spec/ruby/core/method/clone_spec.rb15
-rw-r--r--spec/ruby/core/method/compose_spec.rb3
-rw-r--r--spec/ruby/core/method/dup_spec.rb15
-rw-r--r--spec/ruby/core/method/parameters_spec.rb47
-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/dup.rb32
-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.rb27
-rw-r--r--spec/ruby/core/module/fixtures/module.rb4
-rw-r--r--spec/ruby/core/module/include_spec.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.rb51
-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.rb22
-rw-r--r--spec/ruby/core/module/set_temporary_name_spec.rb113
-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.rb100
-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/clone_spec.rb9
-rw-r--r--spec/ruby/core/proc/compose_spec.rb46
-rw-r--r--spec/ruby/core/proc/dup_spec.rb7
-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.rb50
-rw-r--r--spec/ruby/core/proc/ruby2_keywords_spec.rb22
-rw-r--r--spec/ruby/core/proc/shared/dup.rb31
-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.rb9
-rw-r--r--spec/ruby/core/process/detach_spec.rb35
-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.rb12
-rw-r--r--spec/ruby/core/process/status/wait_spec.rb158
-rw-r--r--spec/ruby/core/process/times_spec.rb22
-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.rb46
-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/case_compare_spec.rb6
-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.rb269
-rw-r--r--spec/ruby/core/refinement/include_spec.rb27
-rw-r--r--spec/ruby/core/refinement/prepend_spec.rb27
-rw-r--r--spec/ruby/core/refinement/refined_class_spec.rb17
-rw-r--r--spec/ruby/core/regexp/initialize_spec.rb14
-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.rb31
-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.rb304
-rw-r--r--spec/ruby/core/string/byterindex_spec.rb359
-rw-r--r--spec/ruby/core/string/byteslice_spec.rb6
-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.rb8
-rw-r--r--spec/ruby/core/string/chomp_spec.rb19
-rw-r--r--spec/ruby/core/string/chop_spec.rb12
-rw-r--r--spec/ruby/core/string/clone_spec.rb4
-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.rb16
-rw-r--r--spec/ruby/core/string/dump_spec.rb22
-rw-r--r--spec/ruby/core/string/dup_spec.rb4
-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/lines_spec.rb1
-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.rb22
-rw-r--r--spec/ruby/core/string/rindex_spec.rb9
-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.rb16
-rw-r--r--spec/ruby/core/string/scrub_spec.rb42
-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.rb24
-rw-r--r--spec/ruby/core/string/shared/partition.rb43
-rw-r--r--spec/ruby/core/string/shared/slice.rb127
-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.rb129
-rw-r--r--spec/ruby/core/string/squeeze_spec.rb17
-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.rb19
-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/undump_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/b_spec.rb32
-rw-r--r--spec/ruby/core/string/unpack/c_spec.rb16
-rw-r--r--spec/ruby/core/string/unpack/h_spec.rb32
-rw-r--r--spec/ruby/core/string/unpack/shared/basic.rb28
-rw-r--r--spec/ruby/core/string/unpack/shared/float.rb68
-rw-r--r--spec/ruby/core/string/unpack/shared/integer.rb100
-rw-r--r--spec/ruby/core/string/unpack/shared/unicode.rb16
-rw-r--r--spec/ruby/core/string/unpack/w_spec.rb16
-rw-r--r--spec/ruby/core/string/unpack1_spec.rb12
-rw-r--r--spec/ruby/core/string/unpack_spec.rb34
-rw-r--r--spec/ruby/core/string/upcase_spec.rb16
-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/utf_8_spec.rb214
-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/struct/values_at_spec.rb55
-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/shared/id2name.rb7
-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/at_spec.rb16
-rw-r--r--spec/ruby/core/time/deconstruct_keys_spec.rb44
-rw-r--r--spec/ruby/core/time/localtime_spec.rb16
-rw-r--r--spec/ruby/core/time/new_spec.rb292
-rw-r--r--spec/ruby/core/time/now_spec.rb66
-rw-r--r--spec/ruby/core/time/shared/gmtime.rb4
-rw-r--r--spec/ruby/core/time/shared/time_params.rb11
-rw-r--r--spec/ruby/core/time/strftime_spec.rb40
-rw-r--r--spec/ruby/core/time/succ_spec.rb39
-rw-r--r--spec/ruby/core/time/utc_spec.rb51
-rw-r--r--spec/ruby/core/time/zone_spec.rb31
-rw-r--r--spec/ruby/core/tracepoint/enable_spec.rb8
-rw-r--r--spec/ruby/core/tracepoint/inspect_spec.rb17
-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/clone_spec.rb13
-rw-r--r--spec/ruby/core/unboundmethod/dup_spec.rb15
-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/shared/dup.rb32
-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/concurrent_require_fixture.rb4
-rw-r--r--spec/ruby/fixtures/code/d/load_fixture.rb.rb1
-rw-r--r--spec/ruby/fixtures/code/load_wrap_fixture.rb12
-rw-r--r--spec/ruby/fixtures/code/wrap_fixture.rb9
-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.rb108
-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.rb50
-rw-r--r--spec/ruby/language/if_spec.rb43
-rw-r--r--spec/ruby/language/keyword_arguments_spec.rb555
-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.rb66
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb276
-rw-r--r--spec/ruby/language/predefined_spec.rb47
-rw-r--r--spec/ruby/language/proc_spec.rb26
-rw-r--r--spec/ruby/language/regexp/character_classes_spec.rb11
-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/return_spec.rb15
-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.rb24
-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.rb14
-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.rb20
-rw-r--r--spec/ruby/library/coverage/supported_spec.rb32
-rw-r--r--spec/ruby/library/date/civil_spec.rb7
-rw-r--r--spec/ruby/library/date/deconstruct_keys_spec.rb44
-rw-r--r--spec/ruby/library/date/iso8601_spec.rb21
-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/shared/parse.rb4
-rw-r--r--spec/ruby/library/date/shared/parse_eu.rb8
-rw-r--r--spec/ruby/library/date/shared/parse_us.rb8
-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/instance/shared/update.rb2
-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/etc/uname_spec.rb14
-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/objectspace/fixtures/trace.rb5
-rw-r--r--spec/ruby/library/objectspace/trace_spec.rb15
-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/fixed_length_secure_compare_spec.rb42
-rw-r--r--spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb168
-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/openssl/secure_compare_spec.rb38
-rw-r--r--spec/ruby/library/openssl/x509/name/verify_spec.rb78
-rw-r--r--spec/ruby/library/openssl/x509/store/verify_spec.rb78
-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/flatten_spec.rb9
-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/proper_subset_spec.rb9
-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/subset_spec.rb9
-rw-r--r--spec/ruby/library/set/to_s_spec.rb1
-rw-r--r--spec/ruby/library/shellwords/shellwords_spec.rb15
-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/gethostname_spec.rb10
-rw-r--r--spec/ruby/library/socket/socket/getnameinfo_spec.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.rb98
-rw-r--r--spec/ruby/library/stringio/lines_spec.rb53
-rw-r--r--spec/ruby/library/stringio/new_spec.rb10
-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.rb46
-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/dump_spec.rb14
-rw-r--r--spec/ruby/library/yaml/dump_stream_spec.rb3
-rw-r--r--spec/ruby/library/yaml/fixtures/common.rb4
-rw-r--r--spec/ruby/library/yaml/load_file_spec.rb13
-rw-r--r--spec/ruby/library/yaml/load_stream_spec.rb3
-rw-r--r--spec/ruby/library/yaml/parse_file_spec.rb8
-rw-r--r--spec/ruby/library/yaml/parse_spec.rb7
-rw-r--r--spec/ruby/library/yaml/shared/each_document.rb3
-rw-r--r--spec/ruby/library/yaml/shared/load.rb10
-rw-r--r--spec/ruby/library/yaml/to_yaml_spec.rb20
-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/array_spec.rb34
-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/array_spec.c28
-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.c8
-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.c116
-rw-r--r--spec/ruby/optional/capi/ext/kernel_spec.c19
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c54
-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/rbasic_spec.c54
-rw-r--r--spec/ruby/optional/capi/ext/rubyspec.h34
-rw-r--r--spec/ruby/optional/capi/ext/string_spec.c35
-rw-r--r--spec/ruby/optional/capi/ext/struct_spec.c13
-rw-r--r--spec/ruby/optional/capi/ext/thread_spec.c9
-rw-r--r--spec/ruby/optional/capi/ext/tracepoint_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/typed_data_spec.c12
-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.rb113
-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/rbasic_spec.rb2
-rw-r--r--spec/ruby/optional/capi/shared/rbasic.rb1
-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/typed_data_spec.rb12
-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/security/cve_2019_8323_spec.rb14
-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.rb57
-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.rb26
-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/exe_cli_spec.rb3
-rw-r--r--spec/syntax_suggest/integration/ruby_command_line_spec.rb26
-rw-r--r--spec/syntax_suggest/integration/syntax_suggest_spec.rb54
-rw-r--r--spec/syntax_suggest/spec_helper.rb6
-rw-r--r--spec/syntax_suggest/unit/api_spec.rb6
-rw-r--r--spec/syntax_suggest/unit/around_block_scan_spec.rb14
-rw-r--r--spec/syntax_suggest/unit/block_expand_spec.rb34
-rw-r--r--spec/syntax_suggest/unit/capture/before_after_keyword_ends_spec.rb47
-rw-r--r--spec/syntax_suggest/unit/capture/falling_indent_lines_spec.rb44
-rw-r--r--spec/syntax_suggest/unit/capture_code_context_spec.rb59
-rw-r--r--spec/syntax_suggest/unit/clean_document_spec.rb55
-rw-r--r--spec/syntax_suggest/unit/code_line_spec.rb13
-rw-r--r--spec/syntax_suggest/unit/code_search_spec.rb82
-rw-r--r--spec/syntax_suggest/unit/core_ext_spec.rb34
-rw-r--r--spec/syntax_suggest/unit/display_invalid_blocks_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/explain_syntax_spec.rb4
-rw-r--r--spec/syntax_suggest/unit/lex_all_spec.rb3
-rw-r--r--spec/syntax_suggest/unit/pathname_from_message_spec.rb9
-rw-r--r--spec/syntax_suggest/unit/scan_history_spec.rb114
-rw-r--r--sprintf.c5
-rw-r--r--st.c206
-rw-r--r--string.c1141
-rw-r--r--string.rb10
-rw-r--r--struct.c160
-rw-r--r--symbol.c85
-rw-r--r--symbol.h5
-rw-r--r--symbol.rb2
-rw-r--r--template/Doxyfile.tmpl363
-rw-r--r--template/GNUmakefile.in9
-rw-r--r--template/Makefile.in139
-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.in10
-rw-r--r--template/id.h.tmpl9
-rw-r--r--template/prelude.c.tmpl30
-rw-r--r--template/ruby.pc.in2
-rwxr-xr-xtemplate/unicode_properties.rdoc.tmpl59
-rw-r--r--test/-ext-/bug_reporter/test_bug_reporter.rb16
-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-/load/test_resolve_symbol.rb27
-rw-r--r--test/-ext-/load/test_stringify_symbols.rb35
-rw-r--r--test/-ext-/postponed_job/test_postponed_job.rb72
-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_set_len.rb29
-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/-ext-/thread/helper.rb51
-rw-r--r--test/-ext-/thread/test_instrumentation_api.rb274
-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_session.rb2
-rw-r--r--test/cgi/test_cgi_util.rb49
-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_address_resolve.rb2
-rw-r--r--test/fiber/test_enumerator.rb8
-rw-r--r--test/fiber/test_io.rb86
-rw-r--r--test/fiber/test_io_buffer.rb74
-rw-r--r--test/fiber/test_process.rb21
-rw-r--r--test/fiber/test_queue.rb20
-rw-r--r--test/fiber/test_scheduler.rb43
-rw-r--r--test/fiber/test_thread.rb22
-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/io/wait/test_io_wait.rb1
-rw-r--r--test/irb/command/test_custom_command.rb149
-rw-r--r--test/irb/command/test_force_exit.rb51
-rw-r--r--test/irb/command/test_help.rb75
-rw-r--r--test/irb/command/test_multi_irb_commands.rb50
-rw-r--r--test/irb/command/test_show_source.rb397
-rw-r--r--test/irb/helper.rb159
-rw-r--r--test/irb/test_cmd.rb692
-rw-r--r--test/irb/test_color.rb65
-rw-r--r--test/irb/test_color_printer.rb20
-rw-r--r--test/irb/test_command.rb971
-rw-r--r--test/irb/test_completion.rb290
-rw-r--r--test/irb/test_context.rb444
-rw-r--r--test/irb/test_debug_cmd.rb303
-rw-r--r--test/irb/test_debugger_integration.rb496
-rw-r--r--test/irb/test_eval_history.rb69
-rw-r--r--test/irb/test_evaluation.rb44
-rw-r--r--test/irb/test_helper_method.rb134
-rw-r--r--test/irb/test_history.rb410
-rw-r--r--test/irb/test_init.rb183
-rw-r--r--test/irb/test_input_method.rb116
-rw-r--r--test/irb/test_irb.rb917
-rw-r--r--test/irb/test_locale.rb118
-rw-r--r--test/irb/test_nesting_parser.rb341
-rw-r--r--test/irb/test_option.rb2
-rw-r--r--test/irb/test_raise_exception.rb74
-rw-r--r--test/irb/test_raise_no_backtrace_exception.rb56
-rw-r--r--test/irb/test_ruby_lex.rb817
-rw-r--r--test/irb/test_tracer.rb90
-rw-r--r--test/irb/test_type_completor.rb88
-rw-r--r--test/irb/test_workspace.rb6
-rw-r--r--test/irb/yamatanooroti/test_rendering.rb716
-rw-r--r--test/json/json_addition_test.rb6
-rw-r--r--test/json/json_common_interface_test.rb34
-rw-r--r--test/json/json_encoding_test.rb9
-rw-r--r--test/json/json_ext_parser_test.rb21
-rw-r--r--test/json/json_fixtures_test.rb2
-rw-r--r--[-rwxr-xr-x]test/json/json_generator_test.rb67
-rw-r--r--test/json/json_generic_object_test.rb4
-rw-r--r--test/json/json_parser_test.rb83
-rw-r--r--test/json/json_string_matching_test.rb2
-rw-r--r--test/json/ractor_test.rb8
-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/monitor/test_monitor.rb2
-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.rb16
-rw-r--r--test/net/http/test_httpresponse.rb39
-rw-r--r--test/net/http/test_https.rb10
-rw-r--r--test/objspace/test_objspace.rb105
-rw-r--r--test/objspace/test_ractor.rb17
-rw-r--r--test/open-uri/test_open-uri.rb32
-rw-r--r--test/openssl/fixtures/pkey/dh1024.pem5
-rw-r--r--test/openssl/fixtures/pkey/dh2048_ffdhe2048.pem8
-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_dh.rb64
-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.rb69
-rw-r--r--test/openssl/test_ssl.rb34
-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.rb57
-rw-r--r--test/optparse/test_getopts.rb16
-rw-r--r--test/ostruct/test_ostruct.rb19
-rw-r--r--test/prism/attribute_write_test.rb60
-rw-r--r--test/prism/bom_test.rb59
-rw-r--r--test/prism/comments_test.rb138
-rw-r--r--test/prism/compiler_test.rb30
-rw-r--r--test/prism/constant_path_node_test.rb56
-rw-r--r--test/prism/desugar_compiler_test.rb86
-rw-r--r--test/prism/dispatcher_test.rb46
-rw-r--r--test/prism/encoding_test.rb349
-rw-r--r--test/prism/errors_test.rb2062
-rw-r--r--test/prism/fixtures/alias.txt23
-rw-r--r--test/prism/fixtures/arithmetic.txt13
-rw-r--r--test/prism/fixtures/arrays.txt142
-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.txt44
-rw-r--r--test/prism/fixtures/classes.txt35
-rw-r--r--test/prism/fixtures/command_method_call.txt41
-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.txt10
-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_comment.txt3
-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_leading_whitespace.txt19
-rw-r--r--test/prism/fixtures/heredocs_nested.txt22
-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.txt149
-rw-r--r--test/prism/fixtures/methods.txt186
-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.txt67
-rw-r--r--test/prism/fixtures/patterns.txt202
-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.txt49
-rw-r--r--test/prism/fixtures/regex.txt40
-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.txt63
-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.txt13
-rw-r--r--test/prism/fixtures/variables.txt47
-rw-r--r--test/prism/fixtures/while.txt23
-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.rb64
-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.rb116
-rw-r--r--test/prism/location_test.rb915
-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.rb283
-rw-r--r--test/prism/pattern_test.rb132
-rw-r--r--test/prism/regexp_test.rb263
-rw-r--r--test/prism/ripper_compat_test.rb19
-rw-r--r--test/prism/ruby_api_test.rb156
-rw-r--r--test/prism/snapshots/alias.txt193
-rw-r--r--test/prism/snapshots/arithmetic.txt252
-rw-r--r--test/prism/snapshots/arrays.txt2268
-rw-r--r--test/prism/snapshots/begin_ensure.txt253
-rw-r--r--test/prism/snapshots/begin_rescue.txt699
-rw-r--r--test/prism/snapshots/blocks.txt777
-rw-r--r--test/prism/snapshots/boolean_operators.txt54
-rw-r--r--test/prism/snapshots/booleans.txt7
-rw-r--r--test/prism/snapshots/break.txt221
-rw-r--r--test/prism/snapshots/case.txt358
-rw-r--r--test/prism/snapshots/classes.txt358
-rw-r--r--test/prism/snapshots/command_method_call.txt718
-rw-r--r--test/prism/snapshots/comments.txt145
-rw-r--r--test/prism/snapshots/constants.txt1237
-rw-r--r--test/prism/snapshots/dash_heredocs.txt254
-rw-r--r--test/prism/snapshots/defined.txt84
-rw-r--r--test/prism/snapshots/dos_endings.txt108
-rw-r--r--test/prism/snapshots/embdoc_no_newline_at_end.txt5
-rw-r--r--test/prism/snapshots/endless_methods.txt106
-rw-r--r--test/prism/snapshots/endless_range_in_conditional.txt49
-rw-r--r--test/prism/snapshots/for.txt176
-rw-r--r--test/prism/snapshots/global_variables.txt191
-rw-r--r--test/prism/snapshots/hashes.txt366
-rw-r--r--test/prism/snapshots/heredoc_with_comment.txt21
-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_leading_whitespace.txt49
-rw-r--r--test/prism/snapshots/heredocs_nested.txt89
-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.txt454
-rw-r--r--test/prism/snapshots/indented_file_end.txt19
-rw-r--r--test/prism/snapshots/integer_operations.txt569
-rw-r--r--test/prism/snapshots/keyword_method_names.txt180
-rw-r--r--test/prism/snapshots/keywords.txt12
-rw-r--r--test/prism/snapshots/lambda.txt200
-rw-r--r--test/prism/snapshots/method_calls.txt2345
-rw-r--r--test/prism/snapshots/methods.txt2072
-rw-r--r--test/prism/snapshots/modules.txt180
-rw-r--r--test/prism/snapshots/newline_terminated.txt107
-rw-r--r--test/prism/snapshots/next.txt132
-rw-r--r--test/prism/snapshots/nils.txt32
-rw-r--r--test/prism/snapshots/non_alphanumeric_methods.txt536
-rw-r--r--test/prism/snapshots/not.txt351
-rw-r--r--test/prism/snapshots/numbers.txt108
-rw-r--r--test/prism/snapshots/patterns.txt4761
-rw-r--r--test/prism/snapshots/procs.txt383
-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.txt492
-rw-r--r--test/prism/snapshots/regex.txt371
-rw-r--r--test/prism/snapshots/rescue.txt390
-rw-r--r--test/prism/snapshots/return.txt138
-rw-r--r--test/prism/snapshots/seattlerb/BEGIN.txt14
-rw-r--r--test/prism/snapshots/seattlerb/TestRubyParserShared.txt357
-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.txt21
-rw-r--r--test/prism/snapshots/seattlerb/and_multi.txt26
-rw-r--r--test/prism/snapshots/seattlerb/aref_args_assocs.txt21
-rw-r--r--test/prism/snapshots/seattlerb/aref_args_lit_assocs.txt23
-rw-r--r--test/prism/snapshots/seattlerb/args_kw_block.txt37
-rw-r--r--test/prism/snapshots/seattlerb/array_line_breaks.txt24
-rw-r--r--test/prism/snapshots/seattlerb/array_lits_trailing_calls.txt35
-rw-r--r--test/prism/snapshots/seattlerb/assoc__bare.txt31
-rw-r--r--test/prism/snapshots/seattlerb/assoc_label.txt33
-rw-r--r--test/prism/snapshots/seattlerb/attr_asgn_colon_id.txt22
-rw-r--r--test/prism/snapshots/seattlerb/attrasgn_array_arg.txt39
-rw-r--r--test/prism/snapshots/seattlerb/attrasgn_array_lhs.txt79
-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.txt31
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_kwsplat.txt39
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_opt_arg_block.txt50
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_opt_splat.txt48
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_opt_splat_arg_block_omfg.txt54
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_optional.txt42
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_scope.txt39
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_scope2.txt41
-rw-r--r--test/prism/snapshots/seattlerb/block_arg_splat_arg.txt43
-rw-r--r--test/prism/snapshots/seattlerb/block_args_kwargs.txt44
-rw-r--r--test/prism/snapshots/seattlerb/block_args_no_kwargs.txt38
-rw-r--r--test/prism/snapshots/seattlerb/block_args_opt1.txt57
-rw-r--r--test/prism/snapshots/seattlerb/block_args_opt2.txt49
-rw-r--r--test/prism/snapshots/seattlerb/block_args_opt2_2.txt67
-rw-r--r--test/prism/snapshots/seattlerb/block_args_opt3.txt74
-rw-r--r--test/prism/snapshots/seattlerb/block_break.txt56
-rw-r--r--test/prism/snapshots/seattlerb/block_call_defn_call_block_call.txt81
-rw-r--r--test/prism/snapshots/seattlerb/block_call_dot_op2_brace_block.txt101
-rw-r--r--test/prism/snapshots/seattlerb/block_call_dot_op2_cmd_args_do_block.txt114
-rw-r--r--test/prism/snapshots/seattlerb/block_call_operation_colon.txt55
-rw-r--r--test/prism/snapshots/seattlerb/block_call_operation_dot.txt55
-rw-r--r--test/prism/snapshots/seattlerb/block_call_paren_call_block_call.txt61
-rw-r--r--test/prism/snapshots/seattlerb/block_command_operation_colon.txt50
-rw-r--r--test/prism/snapshots/seattlerb/block_command_operation_dot.txt50
-rw-r--r--test/prism/snapshots/seattlerb/block_decomp_anon_splat_arg.txt46
-rw-r--r--test/prism/snapshots/seattlerb/block_decomp_arg_splat.txt46
-rw-r--r--test/prism/snapshots/seattlerb/block_decomp_arg_splat_arg.txt50
-rw-r--r--test/prism/snapshots/seattlerb/block_decomp_splat.txt46
-rw-r--r--test/prism/snapshots/seattlerb/block_kw.txt41
-rw-r--r--test/prism/snapshots/seattlerb/block_kw__required.txt38
-rw-r--r--test/prism/snapshots/seattlerb/block_kwarg_lvar.txt50
-rw-r--r--test/prism/snapshots/seattlerb/block_kwarg_lvar_multiple.txt60
-rw-r--r--test/prism/snapshots/seattlerb/block_next.txt56
-rw-r--r--test/prism/snapshots/seattlerb/block_opt_arg.txt44
-rw-r--r--test/prism/snapshots/seattlerb/block_opt_splat.txt46
-rw-r--r--test/prism/snapshots/seattlerb/block_opt_splat_arg_block_omfg.txt52
-rw-r--r--test/prism/snapshots/seattlerb/block_optarg.txt46
-rw-r--r--test/prism/snapshots/seattlerb/block_paren_splat.txt48
-rw-r--r--test/prism/snapshots/seattlerb/block_reg_optarg.txt48
-rw-r--r--test/prism/snapshots/seattlerb/block_return.txt56
-rw-r--r--test/prism/snapshots/seattlerb/block_scope.txt29
-rw-r--r--test/prism/snapshots/seattlerb/block_splat_reg.txt41
-rw-r--r--test/prism/snapshots/seattlerb/bug169.txt29
-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.txt87
-rw-r--r--test/prism/snapshots/seattlerb/bug202.txt20
-rw-r--r--test/prism/snapshots/seattlerb/bug236.txt70
-rw-r--r--test/prism/snapshots/seattlerb/bug290.txt24
-rw-r--r--test/prism/snapshots/seattlerb/bug_187.txt61
-rw-r--r--test/prism/snapshots/seattlerb/bug_215.txt14
-rw-r--r--test/prism/snapshots/seattlerb/bug_249.txt88
-rw-r--r--test/prism/snapshots/seattlerb/bug_and.txt21
-rw-r--r--test/prism/snapshots/seattlerb/bug_args__19.txt57
-rw-r--r--test/prism/snapshots/seattlerb/bug_args_masgn.txt47
-rw-r--r--test/prism/snapshots/seattlerb/bug_args_masgn2.txt55
-rw-r--r--test/prism/snapshots/seattlerb/bug_args_masgn_outer_parens__19.txt53
-rw-r--r--test/prism/snapshots/seattlerb/bug_call_arglist_parens.txt106
-rw-r--r--test/prism/snapshots/seattlerb/bug_case_when_regexp.txt27
-rw-r--r--test/prism/snapshots/seattlerb/bug_comma.txt41
-rw-r--r--test/prism/snapshots/seattlerb/bug_cond_pct.txt21
-rw-r--r--test/prism/snapshots/seattlerb/bug_hash_args.txt38
-rw-r--r--test/prism/snapshots/seattlerb/bug_hash_args_trailing_comma.txt38
-rw-r--r--test/prism/snapshots/seattlerb/bug_hash_interp_array.txt26
-rw-r--r--test/prism/snapshots/seattlerb/bug_masgn_right.txt47
-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.txt31
-rw-r--r--test/prism/snapshots/seattlerb/call_arg_assoc_kwsplat.txt40
-rw-r--r--test/prism/snapshots/seattlerb/call_arg_kwsplat.txt36
-rw-r--r--test/prism/snapshots/seattlerb/call_args_assoc_quoted.txt103
-rw-r--r--test/prism/snapshots/seattlerb/call_args_assoc_trailing_comma.txt31
-rw-r--r--test/prism/snapshots/seattlerb/call_args_command.txt53
-rw-r--r--test/prism/snapshots/seattlerb/call_array_arg.txt37
-rw-r--r--test/prism/snapshots/seattlerb/call_array_block_call.txt41
-rw-r--r--test/prism/snapshots/seattlerb/call_array_lambda_block_call.txt43
-rw-r--r--test/prism/snapshots/seattlerb/call_array_lit_inline_hash.txt44
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc.txt29
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc_new.txt33
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc_new_if_multiline.txt56
-rw-r--r--test/prism/snapshots/seattlerb/call_assoc_trailing_comma.txt29
-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.txt54
-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.txt26
-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.txt41
-rw-r--r--test/prism/snapshots/seattlerb/call_stabby_with_braces_block.txt41
-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.txt940
-rw-r--r--test/prism/snapshots/seattlerb/case_in_31.txt49
-rw-r--r--test/prism/snapshots/seattlerb/case_in_37.txt58
-rw-r--r--test/prism/snapshots/seattlerb/case_in_42.txt44
-rw-r--r--test/prism/snapshots/seattlerb/case_in_42_2.txt40
-rw-r--r--test/prism/snapshots/seattlerb/case_in_47.txt52
-rw-r--r--test/prism/snapshots/seattlerb/case_in_67.txt32
-rw-r--r--test/prism/snapshots/seattlerb/case_in_86.txt52
-rw-r--r--test/prism/snapshots/seattlerb/case_in_86_2.txt52
-rw-r--r--test/prism/snapshots/seattlerb/case_in_array_pat_const.txt42
-rw-r--r--test/prism/snapshots/seattlerb/case_in_array_pat_const2.txt48
-rw-r--r--test/prism/snapshots/seattlerb/case_in_array_pat_paren_assign.txt48
-rw-r--r--test/prism/snapshots/seattlerb/case_in_const.txt28
-rw-r--r--test/prism/snapshots/seattlerb/case_in_else.txt40
-rw-r--r--test/prism/snapshots/seattlerb/case_in_find.txt47
-rw-r--r--test/prism/snapshots/seattlerb/case_in_find_array.txt44
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat.txt68
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_assign.txt81
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_paren_assign.txt50
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_paren_true.txt47
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_rest.txt55
-rw-r--r--test/prism/snapshots/seattlerb/case_in_hash_pat_rest_solo.txt42
-rw-r--r--test/prism/snapshots/seattlerb/case_in_if_unless_post_mod.txt67
-rw-r--r--test/prism/snapshots/seattlerb/case_in_multiple.txt59
-rw-r--r--test/prism/snapshots/seattlerb/case_in_or.txt38
-rw-r--r--test/prism/snapshots/seattlerb/class_comments.txt32
-rw-r--r--test/prism/snapshots/seattlerb/cond_unary_minus.txt14
-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.txt62
-rw-r--r--test/prism/snapshots/seattlerb/defined_eh_parens.txt12
-rw-r--r--test/prism/snapshots/seattlerb/defn_arg_asplat_arg.txt35
-rw-r--r--test/prism/snapshots/seattlerb/defn_arg_forward_args.txt49
-rw-r--r--test/prism/snapshots/seattlerb/defn_args_forward_args.txt59
-rw-r--r--test/prism/snapshots/seattlerb/defn_comments.txt19
-rw-r--r--test/prism/snapshots/seattlerb/defn_endless_command.txt36
-rw-r--r--test/prism/snapshots/seattlerb/defn_endless_command_rescue.txt42
-rw-r--r--test/prism/snapshots/seattlerb/defn_forward_args.txt44
-rw-r--r--test/prism/snapshots/seattlerb/defn_forward_args__no_parens.txt44
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_env.txt55
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_kwarg.txt41
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_kwsplat.txt37
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_kwsplat_anon.txt37
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_lvar.txt42
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_no_parens.txt33
-rw-r--r--test/prism/snapshots/seattlerb/defn_kwarg_val.txt35
-rw-r--r--test/prism/snapshots/seattlerb/defn_no_kwargs.txt30
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner.txt47
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner_eq2.txt46
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner_noargs.txt31
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner_noargs_parentheses.txt31
-rw-r--r--test/prism/snapshots/seattlerb/defn_oneliner_rescue.txt158
-rw-r--r--test/prism/snapshots/seattlerb/defn_opt_last_arg.txt33
-rw-r--r--test/prism/snapshots/seattlerb/defn_opt_reg.txt35
-rw-r--r--test/prism/snapshots/seattlerb/defn_opt_splat_arg.txt40
-rw-r--r--test/prism/snapshots/seattlerb/defn_powarg.txt31
-rw-r--r--test/prism/snapshots/seattlerb/defn_reg_opt_reg.txt42
-rw-r--r--test/prism/snapshots/seattlerb/defn_splat_arg.txt33
-rw-r--r--test/prism/snapshots/seattlerb/defn_unary_not.txt22
-rw-r--r--test/prism/snapshots/seattlerb/defns_reserved.txt20
-rw-r--r--test/prism/snapshots/seattlerb/defs_as_arg_with_do_block_inside.txt62
-rw-r--r--test/prism/snapshots/seattlerb/defs_comments.txt20
-rw-r--r--test/prism/snapshots/seattlerb/defs_endless_command.txt46
-rw-r--r--test/prism/snapshots/seattlerb/defs_endless_command_rescue.txt52
-rw-r--r--test/prism/snapshots/seattlerb/defs_kwarg.txt34
-rw-r--r--test/prism/snapshots/seattlerb/defs_oneliner.txt48
-rw-r--r--test/prism/snapshots/seattlerb/defs_oneliner_eq2.txt47
-rw-r--r--test/prism/snapshots/seattlerb/defs_oneliner_rescue.txt161
-rw-r--r--test/prism/snapshots/seattlerb/difficult0_.txt72
-rw-r--r--test/prism/snapshots/seattlerb/difficult1_line_numbers.txt253
-rw-r--r--test/prism/snapshots/seattlerb/difficult1_line_numbers2.txt76
-rw-r--r--test/prism/snapshots/seattlerb/difficult2_.txt71
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_.txt50
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_2.txt41
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_3.txt45
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_4.txt38
-rw-r--r--test/prism/snapshots/seattlerb/difficult3_5.txt50
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__10.txt50
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__11.txt46
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__12.txt48
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__6.txt52
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__7.txt48
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__8.txt50
-rw-r--r--test/prism/snapshots/seattlerb/difficult3__9.txt48
-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_.txt60
-rw-r--r--test/prism/snapshots/seattlerb/difficult6__7.txt55
-rw-r--r--test/prism/snapshots/seattlerb/difficult6__8.txt55
-rw-r--r--test/prism/snapshots/seattlerb/difficult7_.txt94
-rw-r--r--test/prism/snapshots/seattlerb/do_bug.txt62
-rw-r--r--test/prism/snapshots/seattlerb/do_lambda.txt18
-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.txt34
-rw-r--r--test/prism/snapshots/seattlerb/dstr_str.txt27
-rw-r--r--test/prism/snapshots/seattlerb/dsym_esc_to_sym.txt11
-rw-r--r--test/prism/snapshots/seattlerb/dsym_to_sym.txt37
-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.txt33
-rw-r--r--test/prism/snapshots/seattlerb/f_kw__required.txt30
-rw-r--r--test/prism/snapshots/seattlerb/flip2_env_lvar.txt37
-rw-r--r--test/prism/snapshots/seattlerb/float_with_if_modifier.txt16
-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.txt27
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_lineno.txt25
-rw-r--r--test/prism/snapshots/seattlerb/heredoc_nested.txt40
-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.txt23
-rw-r--r--test/prism/snapshots/seattlerb/if_symbol.txt31
-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.txt17
-rw-r--r--test/prism/snapshots/seattlerb/interpolated_symbol_array_line_breaks.txt24
-rw-r--r--test/prism/snapshots/seattlerb/interpolated_word_array_line_breaks.txt24
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_1.txt39
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_10_1.txt48
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_10_2.txt52
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_11_1.txt50
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_11_2.txt54
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_2__19.txt45
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_3.txt49
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_4.txt43
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_5.txt41
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_6.txt46
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_7_1.txt46
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_7_2.txt50
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_8_1.txt48
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_8_2.txt52
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_9_1.txt44
-rw-r--r--test/prism/snapshots/seattlerb/iter_args_9_2.txt48
-rw-r--r--test/prism/snapshots/seattlerb/iter_kwarg.txt41
-rw-r--r--test/prism/snapshots/seattlerb/iter_kwarg_kwsplat.txt45
-rw-r--r--test/prism/snapshots/seattlerb/label_vs_string.txt34
-rw-r--r--test/prism/snapshots/seattlerb/lambda_do_vs_brace.txt99
-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.txt49
-rw-r--r--test/prism/snapshots/seattlerb/magic_encoding_comment.txt47
-rw-r--r--test/prism/snapshots/seattlerb/masgn_anon_splat_arg.txt29
-rw-r--r--test/prism/snapshots/seattlerb/masgn_arg_colon_arg.txt42
-rw-r--r--test/prism/snapshots/seattlerb/masgn_arg_ident.txt42
-rw-r--r--test/prism/snapshots/seattlerb/masgn_arg_splat_arg.txt35
-rw-r--r--test/prism/snapshots/seattlerb/masgn_colon2.txt41
-rw-r--r--test/prism/snapshots/seattlerb/masgn_colon3.txt34
-rw-r--r--test/prism/snapshots/seattlerb/masgn_command_call.txt42
-rw-r--r--test/prism/snapshots/seattlerb/masgn_double_paren.txt35
-rw-r--r--test/prism/snapshots/seattlerb/masgn_lhs_splat.txt30
-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.txt39
-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.txt30
-rw-r--r--test/prism/snapshots/seattlerb/multiline_hash_declaration.txt95
-rw-r--r--test/prism/snapshots/seattlerb/non_interpolated_symbol_array_line_breaks.txt24
-rw-r--r--test/prism/snapshots/seattlerb/non_interpolated_word_array_line_breaks.txt24
-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.txt51
-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.txt19
-rw-r--r--test/prism/snapshots/seattlerb/parse_if_not_canonical.txt62
-rw-r--r--test/prism/snapshots/seattlerb/parse_if_not_noncanonical.txt62
-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.txt60
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_defn_complex.txt65
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_defn_no_parens.txt33
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_defn_no_parens_args.txt29
-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.txt35
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_hash_lit.txt21
-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.txt73
-rw-r--r--test/prism/snapshots/seattlerb/parse_line_iter_call_parens.txt73
-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.txt39
-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.txt31
-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.txt42
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_058.txt67
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_058_2.txt61
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_069.txt46
-rw-r--r--test/prism/snapshots/seattlerb/parse_pattern_076.txt56
-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.txt52
-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.txt50
-rw-r--r--test/prism/snapshots/seattlerb/pipe_semicolon.txt39
-rw-r--r--test/prism/snapshots/seattlerb/pipe_space.txt37
-rw-r--r--test/prism/snapshots/seattlerb/qWords_space.txt10
-rw-r--r--test/prism/snapshots/seattlerb/qsymbols.txt28
-rw-r--r--test/prism/snapshots/seattlerb/qsymbols_empty.txt10
-rw-r--r--test/prism/snapshots/seattlerb/qsymbols_empty_space.txt10
-rw-r--r--test/prism/snapshots/seattlerb/qsymbols_interp.txt55
-rw-r--r--test/prism/snapshots/seattlerb/quoted_symbol_hash_arg.txt35
-rw-r--r--test/prism/snapshots/seattlerb/quoted_symbol_keys.txt25
-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.txt10
-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.txt33
-rw-r--r--test/prism/snapshots/seattlerb/rescue_do_end_ensure_result.txt59
-rw-r--r--test/prism/snapshots/seattlerb/rescue_do_end_no_raise.txt76
-rw-r--r--test/prism/snapshots/seattlerb/rescue_do_end_raised.txt53
-rw-r--r--test/prism/snapshots/seattlerb/rescue_do_end_rescued.txt80
-rw-r--r--test/prism/snapshots/seattlerb/rescue_in_block.txt48
-rw-r--r--test/prism/snapshots/seattlerb/rescue_parens.txt48
-rw-r--r--test/prism/snapshots/seattlerb/return_call_assocs.txt203
-rw-r--r--test/prism/snapshots/seattlerb/rhs_asgn.txt14
-rw-r--r--test/prism/snapshots/seattlerb/ruby21_numbers.txt24
-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.txt28
-rw-r--r--test/prism/snapshots/seattlerb/stabby_arg_opt_splat_arg_block_omfg.txt45
-rw-r--r--test/prism/snapshots/seattlerb/stabby_block_iter_call.txt60
-rw-r--r--test/prism/snapshots/seattlerb/stabby_block_iter_call_no_target_with_arg.txt55
-rw-r--r--test/prism/snapshots/seattlerb/stabby_block_kw.txt32
-rw-r--r--test/prism/snapshots/seattlerb/stabby_block_kw__required.txt29
-rw-r--r--test/prism/snapshots/seattlerb/stabby_proc_scope.txt30
-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.txt104
-rw-r--r--test/prism/snapshots/seattlerb/str_lit_concat_bad_encodings.txt21
-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.txt11
-rw-r--r--test/prism/snapshots/seattlerb/symbol_list.txt50
-rw-r--r--test/prism/snapshots/seattlerb/symbols.txt28
-rw-r--r--test/prism/snapshots/seattlerb/symbols_empty.txt10
-rw-r--r--test/prism/snapshots/seattlerb/symbols_empty_space.txt10
-rw-r--r--test/prism/snapshots/seattlerb/symbols_interp.txt28
-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.txt21
-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.txt28
-rw-r--r--test/prism/snapshots/seattlerb/yield_arg.txt15
-rw-r--r--test/prism/snapshots/seattlerb/yield_call_assocs.txt215
-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.txt409
-rw-r--r--test/prism/snapshots/strings.txt527
-rw-r--r--test/prism/snapshots/super.txt124
-rw-r--r--test/prism/snapshots/symbols.txt456
-rw-r--r--test/prism/snapshots/ternary_operator.txt293
-rw-r--r--test/prism/snapshots/tilde_heredocs.txt381
-rw-r--r--test/prism/snapshots/undef.txt116
-rw-r--r--test/prism/snapshots/unescaping.txt34
-rw-r--r--test/prism/snapshots/unless.txt132
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/alias.txt29
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/assignment.txt1035
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/block.txt1408
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/case.txt434
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/class.txt234
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/control.txt139
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/def.txt1201
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/defined.txt53
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/defs.txt369
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/dstr.txt340
-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.txt189
-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.txt280
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/kwbegin.txt491
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/lambda.txt149
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/literal.txt1144
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/module.txt108
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/opasgn.txt489
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/pattern.txt424
-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.txt2183
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/since/27.txt49
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/since/30.txt83
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/since/31.txt89
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/since/32.txt106
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/singletons.txt9
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/super.txt282
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/unary.txt245
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/undef.txt29
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/variables.txt53
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/while.txt705
-rw-r--r--test/prism/snapshots/unparser/corpus/literal/yield.txt56
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/and.txt235
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/block.txt195
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/def.txt92
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/dstr.txt570
-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.txt29
-rw-r--r--test/prism/snapshots/unparser/corpus/semantic/while.txt281
-rw-r--r--test/prism/snapshots/until.txt141
-rw-r--r--test/prism/snapshots/variables.txt379
-rw-r--r--test/prism/snapshots/while.txt365
-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.txt21
-rw-r--r--test/prism/snapshots/whitequark/alias_gvar.txt21
-rw-r--r--test/prism/snapshots/whitequark/ambiuous_quoted_label_in_ternary_operator.txt60
-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.txt46
-rw-r--r--test/prism/snapshots/whitequark/arg.txt55
-rw-r--r--test/prism/snapshots/whitequark/arg_duplicate_ignored.txt57
-rw-r--r--test/prism/snapshots/whitequark/arg_label.txt118
-rw-r--r--test/prism/snapshots/whitequark/arg_scope.txt34
-rw-r--r--test/prism/snapshots/whitequark/args.txt1024
-rw-r--r--test/prism/snapshots/whitequark/args_args_assocs.txt94
-rw-r--r--test/prism/snapshots/whitequark/args_args_assocs_comma.txt53
-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.txt189
-rw-r--r--test/prism/snapshots/whitequark/args_assocs_comma.txt43
-rw-r--r--test/prism/snapshots/whitequark/args_assocs_legacy.txt189
-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.txt39
-rw-r--r--test/prism/snapshots/whitequark/array_plain.txt14
-rw-r--r--test/prism/snapshots/whitequark/array_splat.txt65
-rw-r--r--test/prism/snapshots/whitequark/array_symbols.txt22
-rw-r--r--test/prism/snapshots/whitequark/array_symbols_empty.txt15
-rw-r--r--test/prism/snapshots/whitequark/array_symbols_interp.txt67
-rw-r--r--test/prism/snapshots/whitequark/array_words.txt22
-rw-r--r--test/prism/snapshots/whitequark/array_words_empty.txt15
-rw-r--r--test/prism/snapshots/whitequark/array_words_interp.txt78
-rw-r--r--test/prism/snapshots/whitequark/asgn_cmd.txt55
-rw-r--r--test/prism/snapshots/whitequark/asgn_mrhs.txt86
-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.txt50
-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.txt31
-rw-r--r--test/prism/snapshots/whitequark/blockargs.txt1288
-rw-r--r--test/prism/snapshots/whitequark/break.txt56
-rw-r--r--test/prism/snapshots/whitequark/break_block.txt41
-rw-r--r--test/prism/snapshots/whitequark/bug_435.txt38
-rw-r--r--test/prism/snapshots/whitequark/bug_447.txt57
-rw-r--r--test/prism/snapshots/whitequark/bug_452.txt63
-rw-r--r--test/prism/snapshots/whitequark/bug_466.txt68
-rw-r--r--test/prism/snapshots/whitequark/bug_473.txt33
-rw-r--r--test/prism/snapshots/whitequark/bug_480.txt36
-rw-r--r--test/prism/snapshots/whitequark/bug_481.txt51
-rw-r--r--test/prism/snapshots/whitequark/bug_ascii_8bit_in_literal.txt11
-rw-r--r--test/prism/snapshots/whitequark/bug_cmd_string_lookahead.txt31
-rw-r--r--test/prism/snapshots/whitequark/bug_cmdarg.txt108
-rw-r--r--test/prism/snapshots/whitequark/bug_def_no_paren_eql_begin.txt19
-rw-r--r--test/prism/snapshots/whitequark/bug_do_block_in_call_args.txt52
-rw-r--r--test/prism/snapshots/whitequark/bug_do_block_in_cmdarg.txt41
-rw-r--r--test/prism/snapshots/whitequark/bug_do_block_in_hash_brace.txt394
-rw-r--r--test/prism/snapshots/whitequark/bug_heredoc_do.txt31
-rw-r--r--test/prism/snapshots/whitequark/bug_interp_single.txt34
-rw-r--r--test/prism/snapshots/whitequark/bug_lambda_leakage.txt38
-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.txt175
-rw-r--r--test/prism/snapshots/whitequark/class_super.txt18
-rw-r--r--test/prism/snapshots/whitequark/class_super_label.txt35
-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.txt40
-rw-r--r--test/prism/snapshots/whitequark/cond_begin_masgn.txt52
-rw-r--r--test/prism/snapshots/whitequark/cond_eflipflop.txt78
-rw-r--r--test/prism/snapshots/whitequark/cond_iflipflop.txt78
-rw-r--r--test/prism/snapshots/whitequark/cond_match_current_line.txt34
-rw-r--r--test/prism/snapshots/whitequark/const_op_asgn.txt98
-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.txt89
-rw-r--r--test/prism/snapshots/whitequark/defined.txt42
-rw-r--r--test/prism/snapshots/whitequark/defs.txt95
-rw-r--r--test/prism/snapshots/whitequark/empty_stmt.txt5
-rw-r--r--test/prism/snapshots/whitequark/endless_comparison_method.txt221
-rw-r--r--test/prism/snapshots/whitequark/endless_method.txt149
-rw-r--r--test/prism/snapshots/whitequark/endless_method_command_syntax.txt396
-rw-r--r--test/prism/snapshots/whitequark/endless_method_forwarded_args_legacy.txt44
-rw-r--r--test/prism/snapshots/whitequark/endless_method_with_rescue_mod.txt54
-rw-r--r--test/prism/snapshots/whitequark/endless_method_without_args.txt89
-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.txt44
-rw-r--r--test/prism/snapshots/whitequark/forward_arg_with_open_args.txt404
-rw-r--r--test/prism/snapshots/whitequark/forward_args_legacy.txt102
-rw-r--r--test/prism/snapshots/whitequark/forwarded_argument_with_kwrestarg.txt57
-rw-r--r--test/prism/snapshots/whitequark/forwarded_argument_with_restarg.txt54
-rw-r--r--test/prism/snapshots/whitequark/forwarded_kwrestarg.txt52
-rw-r--r--test/prism/snapshots/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt63
-rw-r--r--test/prism/snapshots/whitequark/forwarded_restarg.txt49
-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.txt45
-rw-r--r--test/prism/snapshots/whitequark/hash_kwsplat.txt34
-rw-r--r--test/prism/snapshots/whitequark/hash_label.txt21
-rw-r--r--test/prism/snapshots/whitequark/hash_label_end.txt97
-rw-r--r--test/prism/snapshots/whitequark/hash_pair_value_omission.txt97
-rw-r--r--test/prism/snapshots/whitequark/heredoc.txt23
-rw-r--r--test/prism/snapshots/whitequark/if.txt63
-rw-r--r--test/prism/snapshots/whitequark/if_else.txt95
-rw-r--r--test/prism/snapshots/whitequark/if_elsif.txt63
-rw-r--r--test/prism/snapshots/whitequark/if_masgn__24.txt42
-rw-r--r--test/prism/snapshots/whitequark/if_mod.txt34
-rw-r--r--test/prism/snapshots/whitequark/if_nl_then.txt34
-rw-r--r--test/prism/snapshots/whitequark/if_while_after_class__since_32.txt119
-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.txt273
-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.txt65
-rw-r--r--test/prism/snapshots/whitequark/kwarg.txt30
-rw-r--r--test/prism/snapshots/whitequark/kwbegin_compstmt.txt34
-rw-r--r--test/prism/snapshots/whitequark/kwnilarg.txt87
-rw-r--r--test/prism/snapshots/whitequark/kwoptarg.txt33
-rw-r--r--test/prism/snapshots/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt57
-rw-r--r--test/prism/snapshots/whitequark/kwrestarg_named.txt31
-rw-r--r--test/prism/snapshots/whitequark/kwrestarg_unnamed.txt31
-rw-r--r--test/prism/snapshots/whitequark/lbrace_arg_after_command_args.txt56
-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.txt39
-rw-r--r--test/prism/snapshots/whitequark/lvasgn.txt16
-rw-r--r--test/prism/snapshots/whitequark/masgn.txt77
-rw-r--r--test/prism/snapshots/whitequark/masgn_attr.txt80
-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.txt66
-rw-r--r--test/prism/snapshots/whitequark/masgn_splat.txt284
-rw-r--r--test/prism/snapshots/whitequark/method_definition_in_while_cond.txt205
-rw-r--r--test/prism/snapshots/whitequark/module.txt14
-rw-r--r--test/prism/snapshots/whitequark/multiple_pattern_matches.txt149
-rw-r--r--test/prism/snapshots/whitequark/newline_in_hash_argument.txt149
-rw-r--r--test/prism/snapshots/whitequark/next.txt56
-rw-r--r--test/prism/snapshots/whitequark/next_block.txt41
-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.txt59
-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.txt147
-rw-r--r--test/prism/snapshots/whitequark/numparam_outside_block.txt115
-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.txt70
-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.txt42
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_490.txt109
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_507.txt36
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_518.txt18
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_525.txt67
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_604.txt58
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_640.txt11
-rw-r--r--test/prism/snapshots/whitequark/parser_bug_645.txt35
-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.txt139
-rw-r--r--test/prism/snapshots/whitequark/pattern_matching__FILE__LINE_literals.txt51
-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.txt233
-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.txt77
-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.txt27
-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.txt42
-rw-r--r--test/prism/snapshots/whitequark/rescue_mod_op_assign.txt36
-rw-r--r--test/prism/snapshots/whitequark/rescue_without_begin_end.txt60
-rw-r--r--test/prism/snapshots/whitequark/restarg_named.txt31
-rw-r--r--test/prism/snapshots/whitequark/restarg_unnamed.txt31
-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.txt41
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_10279.txt31
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_10653.txt175
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11107.txt50
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11380.txt56
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11873.txt785
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11873_a.txt1245
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11873_b.txt100
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11989.txt24
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_11990.txt34
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12073.txt94
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12402.txt565
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12669.txt133
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_12686.txt39
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_13547.txt32
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_14690.txt61
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_15789.txt122
-rw-r--r--test/prism/snapshots/whitequark/ruby_bug_9669.txt57
-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.txt328
-rw-r--r--test/prism/snapshots/whitequark/send_block_conditional.txt32
-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.txt46
-rw-r--r--test/prism/snapshots/whitequark/send_lambda_args.txt51
-rw-r--r--test/prism/snapshots/whitequark/send_lambda_args_noparen.txt56
-rw-r--r--test/prism/snapshots/whitequark/send_lambda_args_shadow.txt32
-rw-r--r--test/prism/snapshots/whitequark/send_lambda_legacy.txt13
-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.txt78
-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.txt109
-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.txt29
-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.txt30
-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.txt50
-rw-r--r--test/prism/snapshots/whitequark/symbol_interp.txt37
-rw-r--r--test/prism/snapshots/whitequark/symbol_plain.txt17
-rw-r--r--test/prism/snapshots/whitequark/ternary.txt34
-rw-r--r--test/prism/snapshots/whitequark/ternary_ambiguous_symbol.txt49
-rw-r--r--test/prism/snapshots/whitequark/trailing_forward_arg.txt53
-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.txt38
-rw-r--r--test/prism/snapshots/whitequark/unless.txt63
-rw-r--r--test/prism/snapshots/whitequark/unless_else.txt95
-rw-r--r--test/prism/snapshots/whitequark/unless_mod.txt34
-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.txt54
-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.txt11
-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.txt55
-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_object_references.rb8
-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_to_ruby.rb2
-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_json_index.rb14
-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_formatter.rb6
-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.rb41
-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.rb39
-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_rdoc.rb14
-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.rb17
-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.rb952
-rw-r--r--test/readline/test_readline_history.rb292
-rw-r--r--test/reline/helper.rb121
-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.rb252
-rw-r--r--test/reline/test_face.rb257
-rw-r--r--test/reline/test_history.rb2
-rw-r--r--test/reline/test_key_actor_emacs.rb2059
-rw-r--r--test/reline/test_key_actor_vi.rb1348
-rw-r--r--test/reline/test_key_stroke.rb68
-rw-r--r--test/reline/test_line_editor.rb183
-rw-r--r--test/reline/test_macro.rb3
-rw-r--r--test/reline/test_reline.rb72
-rw-r--r--test/reline/test_reline_key.rb50
-rw-r--r--test/reline/test_string_processing.rb14
-rw-r--r--test/reline/test_terminfo.rb2
-rw-r--r--test/reline/test_unicode.rb67
-rw-r--r--test/reline/test_within_pipe.rb9
-rwxr-xr-xtest/reline/yamatanooroti/multiline_repl64
-rw-r--r--test/reline/yamatanooroti/termination_checker.rb38
-rw-r--r--test/reline/yamatanooroti/test_rendering.rb726
-rw-r--r--test/resolv/test_dns.rb201
-rw-r--r--test/resolv/test_resource.rb8
-rw-r--r--test/resolv/test_svcb_https.rb231
-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.rb145
-rw-r--r--test/ripper/test_parser_events.rb20
-rw-r--r--test/ripper/test_ripper.rb29
-rw-r--r--test/ripper/test_scanner_events.rb39
-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_cesu8.rb4
-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.rb368
-rw-r--r--test/ruby/test_arity.rb1
-rw-r--r--test/ruby/test_array.rb35
-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_bignum.rb6
-rw-r--r--test/ruby/test_call.rb1224
-rw-r--r--test/ruby/test_class.rb18
-rw-r--r--test/ruby/test_clone.rb7
-rw-r--r--test/ruby/test_comparable.rb10
-rw-r--r--test/ruby/test_compile_prism.rb2110
-rw-r--r--test/ruby/test_complex.rb105
-rw-r--r--test/ruby/test_data.rb34
-rw-r--r--test/ruby/test_default_gems.rb19
-rw-r--r--test/ruby/test_defined.rb14
-rw-r--r--test/ruby/test_dir.rb96
-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.rb71
-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.rb395
-rw-r--r--test/ruby/test_gc_compact.rb134
-rw-r--r--test/ruby/test_hash.rb800
-rw-r--r--test/ruby/test_integer.rb105
-rw-r--r--test/ruby/test_integer_comb.rb23
-rw-r--r--test/ruby/test_io.rb242
-rw-r--r--test/ruby/test_io_buffer.rb192
-rw-r--r--test/ruby/test_io_m17n.rb104
-rw-r--r--test/ruby/test_iseq.rb88
-rw-r--r--test/ruby/test_keyword.rb54
-rw-r--r--test/ruby/test_lambda.rb26
-rw-r--r--test/ruby/test_lazy_enumerator.rb5
-rw-r--r--test/ruby/test_m17n.rb35
-rw-r--r--test/ruby/test_marshal.rb19
-rw-r--r--test/ruby/test_math.rb10
-rw-r--r--test/ruby/test_method.rb91
-rw-r--r--test/ruby/test_mjit.rb1327
-rw-r--r--test/ruby/test_mjit_debug.rb17
-rw-r--r--test/ruby/test_module.rb130
-rw-r--r--test/ruby/test_nomethod_error.rb2
-rw-r--r--test/ruby/test_numeric.rb3
-rw-r--r--test/ruby/test_object.rb47
-rw-r--r--test/ruby/test_optimization.rb27
-rw-r--r--test/ruby/test_pack.rb54
-rw-r--r--test/ruby/test_parse.rb266
-rw-r--r--test/ruby/test_pattern_matching.rb18
-rw-r--r--test/ruby/test_proc.rb112
-rw-r--r--test/ruby/test_process.rb204
-rw-r--r--test/ruby/test_random_formatter.rb55
-rw-r--r--test/ruby/test_range.rb301
-rw-r--r--test/ruby/test_refinement.rb69
-rw-r--r--test/ruby/test_regexp.rb433
-rw-r--r--test/ruby/test_require.rb76
-rw-r--r--test/ruby/test_require_lib.rb31
-rw-r--r--test/ruby/test_rubyoptions.rb296
-rw-r--r--test/ruby/test_rubyvm_mjit.rb105
-rw-r--r--test/ruby/test_settracefunc.rb247
-rw-r--r--test/ruby/test_shapes.rb646
-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.rb605
-rw-r--r--test/ruby/test_string_memory.rb55
-rw-r--r--test/ruby/test_struct.rb22
-rw-r--r--test/ruby/test_super.rb41
-rw-r--r--test/ruby/test_symbol.rb7
-rw-r--r--test/ruby/test_syntax.rb297
-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.rb30
-rw-r--r--test/ruby/test_time_tz.rb10
-rw-r--r--test/ruby/test_transcode.rb498
-rw-r--r--test/ruby/test_variable.rb124
-rw-r--r--test/ruby/test_weakkeymap.rb159
-rw-r--r--test/ruby/test_weakmap.rb89
-rw-r--r--test/ruby/test_whileuntil.rb18
-rw-r--r--test/ruby/test_yjit.rb537
-rw-r--r--test/ruby/test_yjit_exit_locations.rb20
-rw-r--r--test/rubygems/bad_rake.rb1
-rw-r--r--test/rubygems/bundler_test_gem.rb55
-rw-r--r--test/rubygems/fake_certlib/openssl.rb1
-rw-r--r--test/rubygems/good_rake.rb1
-rw-r--r--test/rubygems/helper.rb385
-rw-r--r--test/rubygems/installer_test_case.rb23
-rw-r--r--test/rubygems/mock_gem_ui.rb86
-rw-r--r--test/rubygems/multifactor_auth_utilities.rb111
-rw-r--r--test/rubygems/package/tar_test_case.rb68
-rw-r--r--test/rubygems/plugin/exception/rubygems_plugin.rb3
-rw-r--r--test/rubygems/plugin/load/rubygems_plugin.rb1
-rw-r--r--test/rubygems/plugin/scripterror/rubygems_plugin.rb4
-rw-r--r--test/rubygems/plugin/standarderror/rubygems_plugin.rb1
-rw-r--r--test/rubygems/rubygems/commands/crash_command.rb1
-rw-r--r--test/rubygems/rubygems/commands/ins_command.rb7
-rw-r--r--test/rubygems/rubygems/commands/interrupt_command.rb11
-rw-r--r--test/rubygems/rubygems_plugin.rb20
-rw-r--r--test/rubygems/simple_gem.rb3
-rw-r--r--test/rubygems/specifications/bar-0.0.2.gemspec2
-rw-r--r--test/rubygems/specifications/rubyforge-0.0.1.gemspec23
-rw-r--r--test/rubygems/test_bundled_ca.rb9
-rw-r--r--test/rubygems/test_config.rb7
-rw-r--r--test/rubygems/test_deprecate.rb11
-rw-r--r--test/rubygems/test_exit.rb2
-rw-r--r--test/rubygems/test_gem.rb262
-rw-r--r--test/rubygems/test_gem_available_set.rb7
-rw-r--r--test/rubygems/test_gem_bundler_version_finder.rb9
-rw-r--r--test/rubygems/test_gem_ci_detector.rb32
-rw-r--r--test/rubygems/test_gem_command.rb48
-rw-r--r--test/rubygems/test_gem_command_manager.rb103
-rw-r--r--test/rubygems/test_gem_commands_build_command.rb18
-rw-r--r--test/rubygems/test_gem_commands_cert_command.rb68
-rw-r--r--test/rubygems/test_gem_commands_check_command.rb1
-rw-r--r--test/rubygems/test_gem_commands_cleanup_command.rb19
-rw-r--r--test/rubygems/test_gem_commands_contents_command.rb21
-rw-r--r--test/rubygems/test_gem_commands_dependency_command.rb1
-rw-r--r--test/rubygems/test_gem_commands_environment_command.rb50
-rw-r--r--test/rubygems/test_gem_commands_exec_command.rb856
-rw-r--r--test/rubygems/test_gem_commands_fetch_command.rb83
-rw-r--r--test/rubygems/test_gem_commands_generate_index_command.rb80
-rw-r--r--test/rubygems/test_gem_commands_help_command.rb7
-rw-r--r--test/rubygems/test_gem_commands_info_command.rb13
-rw-r--r--test/rubygems/test_gem_commands_install_command.rb125
-rw-r--r--test/rubygems/test_gem_commands_list_command.rb30
-rw-r--r--test/rubygems/test_gem_commands_lock_command.rb5
-rw-r--r--test/rubygems/test_gem_commands_mirror.rb3
-rw-r--r--test/rubygems/test_gem_commands_open_command.rb14
-rw-r--r--test/rubygems/test_gem_commands_outdated_command.rb1
-rw-r--r--test/rubygems/test_gem_commands_owner_command.rb142
-rw-r--r--test/rubygems/test_gem_commands_pristine_command.rb97
-rw-r--r--test/rubygems/test_gem_commands_push_command.rb149
-rw-r--r--test/rubygems/test_gem_commands_query_command.rb65
-rw-r--r--test/rubygems/test_gem_commands_rebuild_command.rb145
-rw-r--r--test/rubygems/test_gem_commands_search_command.rb1
-rw-r--r--test/rubygems/test_gem_commands_server_command.rb3
-rw-r--r--test/rubygems/test_gem_commands_setup_command.rb59
-rw-r--r--test/rubygems/test_gem_commands_signin_command.rb100
-rw-r--r--test/rubygems/test_gem_commands_signout_command.rb6
-rw-r--r--test/rubygems/test_gem_commands_sources_command.rb1
-rw-r--r--test/rubygems/test_gem_commands_specification_command.rb31
-rw-r--r--test/rubygems/test_gem_commands_stale_command.rb5
-rw-r--r--test/rubygems/test_gem_commands_uninstall_command.rb133
-rw-r--r--test/rubygems/test_gem_commands_unpack_command.rb9
-rw-r--r--test/rubygems/test_gem_commands_update_command.rb65
-rw-r--r--test/rubygems/test_gem_commands_which_command.rb13
-rw-r--r--test/rubygems/test_gem_commands_yank_command.rb129
-rw-r--r--test/rubygems/test_gem_config_file.rb164
-rw-r--r--test/rubygems/test_gem_console_ui.rb19
-rw-r--r--test/rubygems/test_gem_dependency.rb22
-rw-r--r--test/rubygems/test_gem_dependency_installer.rb256
-rw-r--r--test/rubygems/test_gem_dependency_list.rb13
-rw-r--r--test/rubygems/test_gem_dependency_resolution_error.rb15
-rw-r--r--test/rubygems/test_gem_doctor.rb1
-rw-r--r--test/rubygems/test_gem_ext_builder.rb161
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder.rb21
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/custom_name.gemspec2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock44
-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/custom_name/lib/custom_name.rb2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock44
-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/rust_ruby_example/rust_ruby_example.gemspec2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb1
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder_unit.rb2
-rw-r--r--test/rubygems/test_gem_ext_cmake_builder.rb15
-rw-r--r--test/rubygems/test_gem_ext_configure_builder.rb3
-rw-r--r--test/rubygems/test_gem_ext_ext_conf_builder.rb17
-rw-r--r--test/rubygems/test_gem_ext_rake_builder.rb23
-rw-r--r--test/rubygems/test_gem_gem_runner.rb10
-rw-r--r--test/rubygems/test_gem_gemcutter_utilities.rb217
-rw-r--r--test/rubygems/test_gem_impossible_dependencies_error.rb1
-rw-r--r--test/rubygems/test_gem_indexer.rb380
-rw-r--r--test/rubygems/test_gem_install_update_options.rb26
-rw-r--r--test/rubygems/test_gem_installer.rb373
-rw-r--r--test/rubygems/test_gem_local_remote_options.rb13
-rw-r--r--test/rubygems/test_gem_name_tuple.rb34
-rw-r--r--test/rubygems/test_gem_package.rb304
-rw-r--r--test/rubygems/test_gem_package_old.rb7
-rw-r--r--test/rubygems/test_gem_package_tar_header.rb91
-rw-r--r--test/rubygems/test_gem_package_tar_reader.rb69
-rw-r--r--test/rubygems/test_gem_package_tar_reader_entry.rb218
-rw-r--r--test/rubygems/test_gem_package_tar_writer.rb89
-rw-r--r--test/rubygems/test_gem_package_task.rb5
-rw-r--r--test/rubygems/test_gem_path_support.rb1
-rw-r--r--test/rubygems/test_gem_platform.rb93
-rw-r--r--test/rubygems/test_gem_rdoc.rb7
-rw-r--r--test/rubygems/test_gem_remote_fetcher.rb734
-rw-r--r--test/rubygems/test_gem_remote_fetcher_local_server.rb220
-rw-r--r--test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb195
-rw-r--r--test/rubygems/test_gem_remote_fetcher_s3.rb233
-rw-r--r--test/rubygems/test_gem_request.rb121
-rw-r--r--test/rubygems/test_gem_request_connection_pools.rb25
-rw-r--r--test/rubygems/test_gem_request_set.rb59
-rw-r--r--test/rubygems/test_gem_request_set_gem_dependency_api.rb183
-rw-r--r--test/rubygems/test_gem_request_set_lockfile.rb1
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_parser.rb21
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_tokenizer.rb1
-rw-r--r--test/rubygems/test_gem_requirement.rb19
-rw-r--r--test/rubygems/test_gem_resolver.rb83
-rw-r--r--test/rubygems/test_gem_resolver_activation_request.rb15
-rw-r--r--test/rubygems/test_gem_resolver_api_set.rb131
-rw-r--r--test/rubygems/test_gem_resolver_api_specification.rb69
-rw-r--r--test/rubygems/test_gem_resolver_best_set.rb105
-rw-r--r--test/rubygems/test_gem_resolver_composed_set.rb1
-rw-r--r--test/rubygems/test_gem_resolver_conflict.rb11
-rw-r--r--test/rubygems/test_gem_resolver_dependency_request.rb25
-rw-r--r--test/rubygems/test_gem_resolver_git_set.rb19
-rw-r--r--test/rubygems/test_gem_resolver_git_specification.rb8
-rw-r--r--test/rubygems/test_gem_resolver_index_set.rb29
-rw-r--r--test/rubygems/test_gem_resolver_index_specification.rb10
-rw-r--r--test/rubygems/test_gem_resolver_installed_specification.rb1
-rw-r--r--test/rubygems/test_gem_resolver_installer_set.rb23
-rw-r--r--test/rubygems/test_gem_resolver_local_specification.rb1
-rw-r--r--test/rubygems/test_gem_resolver_lock_set.rb7
-rw-r--r--test/rubygems/test_gem_resolver_lock_specification.rb15
-rw-r--r--test/rubygems/test_gem_resolver_requirement_list.rb1
-rw-r--r--test/rubygems/test_gem_resolver_specification.rb3
-rw-r--r--test/rubygems/test_gem_resolver_vendor_set.rb1
-rw-r--r--test/rubygems/test_gem_resolver_vendor_specification.rb4
-rw-r--r--test/rubygems/test_gem_safe_marshal.rb416
-rw-r--r--test/rubygems/test_gem_safe_yaml.rb24
-rw-r--r--test/rubygems/test_gem_security.rb61
-rw-r--r--test/rubygems/test_gem_security_policy.rb60
-rw-r--r--test/rubygems/test_gem_security_signer.rb19
-rw-r--r--test/rubygems/test_gem_security_trust_dir.rb19
-rw-r--r--test/rubygems/test_gem_silent_ui.rb4
-rw-r--r--test/rubygems/test_gem_source.rb43
-rw-r--r--test/rubygems/test_gem_source_fetch_problem.rb1
-rw-r--r--test/rubygems/test_gem_source_git.rb40
-rw-r--r--test/rubygems/test_gem_source_installed.rb10
-rw-r--r--test/rubygems/test_gem_source_list.rb5
-rw-r--r--test/rubygems/test_gem_source_local.rb10
-rw-r--r--test/rubygems/test_gem_source_lock.rb11
-rw-r--r--test/rubygems/test_gem_source_specific_file.rb9
-rw-r--r--test/rubygems/test_gem_source_subpath_problem.rb9
-rw-r--r--test/rubygems/test_gem_source_vendor.rb5
-rw-r--r--test/rubygems/test_gem_spec_fetcher.rb31
-rw-r--r--test/rubygems/test_gem_specification.rb587
-rw-r--r--test/rubygems/test_gem_stream_ui.rb53
-rw-r--r--test/rubygems/test_gem_stub_specification.rb98
-rw-r--r--test/rubygems/test_gem_text.rb1
-rw-r--r--test/rubygems/test_gem_uninstaller.rb200
-rw-r--r--test/rubygems/test_gem_unsatisfiable_dependency_error.rb1
-rw-r--r--test/rubygems/test_gem_update_suggestion.rb153
-rw-r--r--test/rubygems/test_gem_uri.rb2
-rw-r--r--test/rubygems/test_gem_uri_formatter.rb1
-rw-r--r--test/rubygems/test_gem_util.rb15
-rw-r--r--test/rubygems/test_gem_version.rb11
-rw-r--r--test/rubygems/test_gem_version_option.rb49
-rw-r--r--test/rubygems/test_kernel.rb31
-rw-r--r--test/rubygems/test_project_sanity.rb35
-rw-r--r--test/rubygems/test_remote_fetch_error.rb5
-rw-r--r--test/rubygems/test_require.rb155
-rw-r--r--test/rubygems/test_rubygems.rb12
-rw-r--r--test/rubygems/test_webauthn_listener.rb143
-rw-r--r--test/rubygems/test_webauthn_listener_response.rb93
-rw-r--r--test/rubygems/test_webauthn_poller.rb134
-rw-r--r--test/rubygems/utilities.rb73
-rw-r--r--test/runner.rb13
-rw-r--r--test/set/test_set.rb892
-rw-r--r--test/socket/test_addrinfo.rb4
-rw-r--r--test/socket/test_socket.rb36
-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/strscan/test_stringscanner.rb60
-rw-r--r--test/test_bundled_gems.rb35
-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_time.rb9
-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.rb19
-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.rb30
-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.rb55
-rw-r--r--thread.c877
-rw-r--r--thread_none.c58
-rw-r--r--thread_none.h1
-rw-r--r--thread_pthread.c3265
-rw-r--r--thread_pthread.h121
-rw-r--r--thread_pthread_mn.c1046
-rw-r--r--thread_sync.c265
-rw-r--r--thread_win32.c196
-rw-r--r--thread_win32.h7
-rw-r--r--time.c446
-rw-r--r--timev.h11
-rw-r--r--timev.rb65
-rw-r--r--tool/bundler/dev_gems.rb9
-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.rb15
-rw-r--r--tool/bundler/test_gems.rb.lock45
-rw-r--r--tool/bundler/vendor_gems.rb15
-rw-r--r--tool/bundler/vendor_gems.rb.lock71
-rw-r--r--tool/ci_functions.sh29
-rwxr-xr-xtool/darwin-ar6
-rwxr-xr-xtool/darwin-cc3
-rw-r--r--tool/downloader.rb1
-rw-r--r--tool/dummy-rake-compiler/rake/extensiontask.rb9
-rwxr-xr-xtool/enc-case-folding.rb6
-rwxr-xr-xtool/enc-unicode.rb101
-rwxr-xr-xtool/extlibs.rb2
-rw-r--r--tool/fake.rb9
-rwxr-xr-xtool/fetch-bundled_gems.rb10
-rwxr-xr-xtool/format-release4
-rwxr-xr-xtool/gen-github-release.rb59
-rwxr-xr-xtool/leaked-globals44
-rw-r--r--tool/lib/bundled_gem.rb64
-rw-r--r--tool/lib/colorize.rb32
-rw-r--r--tool/lib/core_assertions.rb119
-rw-r--r--tool/lib/envutil.rb49
-rw-r--r--tool/lib/iseq_loader_checker.rb9
-rw-r--r--tool/lib/leakchecker.rb5
-rw-r--r--tool/lib/memory_status.rb2
-rw-r--r--tool/lib/output.rb12
-rw-r--r--tool/lib/test/unit.rb112
-rw-r--r--tool/lib/test/unit/parallel.rb12
-rw-r--r--tool/lib/test/unit/testcase.rb22
-rw-r--r--tool/lib/vcs.rb59
-rwxr-xr-xtool/ln_sr.rb2
-rw-r--r--tool/lrama/LEGAL.md12
-rw-r--r--tool/lrama/MIT21
-rw-r--r--tool/lrama/NEWS.md167
-rwxr-xr-xtool/lrama/exe/lrama6
-rw-r--r--tool/lrama/lib/lrama.rb17
-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.rb517
-rw-r--r--tool/lrama/lib/lrama/counterexamples.rb286
-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.rb23
-rw-r--r--tool/lrama/lib/lrama/counterexamples/production_path.rb17
-rw-r--r--tool/lrama/lib/lrama/counterexamples/start_path.rb21
-rw-r--r--tool/lrama/lib/lrama/counterexamples/state_item.rb6
-rw-r--r--tool/lrama/lib/lrama/counterexamples/transition_path.rb17
-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.rb612
-rw-r--r--tool/lrama/lib/lrama/grammar/auxiliary.rb7
-rw-r--r--tool/lrama/lib/lrama/grammar/code.rb38
-rw-r--r--tool/lrama/lib/lrama/grammar/code/initial_action_code.rb28
-rw-r--r--tool/lrama/lib/lrama/grammar/code/no_reference_code.rb24
-rw-r--r--tool/lrama/lib/lrama/grammar/code/printer_code.rb34
-rw-r--r--tool/lrama/lib/lrama/grammar/code/rule_action.rb78
-rw-r--r--tool/lrama/lib/lrama/grammar/counter.rb15
-rw-r--r--tool/lrama/lib/lrama/grammar/error_token.rb9
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rules/builder.rb60
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rules/builder/base.rb36
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rules/builder/list.rb28
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rules/builder/nonempty_list.rb28
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rules/builder/option.rb28
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rules/builder/separated_list.rb39
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rules/builder/separated_nonempty_list.rb34
-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.rb13
-rw-r--r--tool/lrama/lib/lrama/grammar/rule.rb56
-rw-r--r--tool/lrama/lib/lrama/grammar/rule_builder.rb177
-rw-r--r--tool/lrama/lib/lrama/grammar/symbol.rb101
-rw-r--r--tool/lrama/lib/lrama/grammar/type.rb6
-rw-r--r--tool/lrama/lib/lrama/grammar/union.rb10
-rw-r--r--tool/lrama/lib/lrama/lexer.rb174
-rw-r--r--tool/lrama/lib/lrama/lexer/location.rb22
-rw-r--r--tool/lrama/lib/lrama/lexer/token.rb51
-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.rb34
-rw-r--r--tool/lrama/lib/lrama/lexer/token/tag.rb12
-rw-r--r--tool/lrama/lib/lrama/lexer/token/user_code.rb64
-rw-r--r--tool/lrama/lib/lrama/option_parser.rb128
-rw-r--r--tool/lrama/lib/lrama/options.rb23
-rw-r--r--tool/lrama/lib/lrama/output.rb417
-rw-r--r--tool/lrama/lib/lrama/parser.rb1934
-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.rb14
-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/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.c2052
-rw-r--r--tool/lrama/template/bison/yacc.h40
-rw-r--r--tool/m4/ruby_check_header.m48
-rw-r--r--tool/m4/ruby_default_arch.m425
-rw-r--r--tool/m4/ruby_stack_grow_direction.m42
-rw-r--r--tool/m4/ruby_try_cflags.m413
-rw-r--r--tool/m4/ruby_universal_arch.m46
-rwxr-xr-xtool/make-snapshot44
-rwxr-xr-xtool/merger.rb186
-rwxr-xr-xtool/missing-baseruby.bat5
-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.rb79
-rwxr-xr-xtool/mkconfig.rb18
-rwxr-xr-xtool/rbinstall.rb127
-rw-r--r--tool/rbs_skip_tests26
-rwxr-xr-xtool/redmine-backporter.rb137
-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.rb9
-rwxr-xr-xtool/sync_default_gems.rb499
-rw-r--r--tool/test-bundled-gems.rb24
-rw-r--r--tool/test-coverage.rb21
-rw-r--r--tool/test/init.rb18
-rw-r--r--tool/test/runner.rb13
-rwxr-xr-xtool/test/test_sync_default_gems.rb221
-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/test_for_warn_bundled_gems/.gitignore1
-rw-r--r--tool/test_for_warn_bundled_gems/Gemfile0
-rw-r--r--tool/test_for_warn_bundled_gems/Gemfile.lock11
-rw-r--r--tool/test_for_warn_bundled_gems/README.md3
-rwxr-xr-xtool/test_for_warn_bundled_gems/test.sh57
-rw-r--r--tool/test_for_warn_bundled_gems/test_no_warn_dash_gem.rb8
-rw-r--r--tool/test_for_warn_bundled_gems/test_no_warn_dependency.rb10
-rw-r--r--tool/test_for_warn_bundled_gems/test_no_warn_sub_feature.rb8
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bootsnap.rb11
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bootsnap_rubyarchdir_gem.rb11
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bundle_exec.rb1
-rwxr-xr-xtool/test_for_warn_bundled_gems/test_warn_bundle_exec_shebang.rb3
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bundled_gems.rb8
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_dash_gem.rb7
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_dependency.rb8
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_redefined.rb18
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_sub_feature.rb7
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_zeitwerk.rb12
-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.rb14
-rw-r--r--transcode.c41
-rw-r--r--transient_heap.c991
-rw-r--r--transient_heap.h65
-rw-r--r--universal_parser.c377
-rw-r--r--util.c15
-rw-r--r--variable.c1342
-rw-r--r--variable.h16
-rw-r--r--version.c97
-rw-r--r--version.h14
-rw-r--r--vm.c808
-rw-r--r--vm_args.c192
-rw-r--r--vm_backtrace.c155
-rw-r--r--vm_callinfo.h126
-rw-r--r--vm_core.h312
-rw-r--r--vm_dump.c428
-rw-r--r--vm_eval.c231
-rw-r--r--vm_exec.c59
-rw-r--r--vm_exec.h36
-rw-r--r--vm_insnhelper.c1511
-rw-r--r--vm_insnhelper.h31
-rw-r--r--vm_method.c370
-rw-r--r--vm_opts.h6
-rw-r--r--vm_sync.c123
-rw-r--r--vm_trace.c453
-rw-r--r--vsnprintf.c4
-rw-r--r--warning.rb4
-rw-r--r--wasm/runtime.c7
-rw-r--r--wasm/setjmp.c69
-rw-r--r--wasm/setjmp.h2
-rw-r--r--weakmap.c1153
-rw-r--r--win32/.document1
-rw-r--r--win32/Makefile.sub81
-rw-r--r--win32/README.win32149
-rw-r--r--win32/file.c27
-rw-r--r--win32/file.h3
-rwxr-xr-xwin32/mkexports.rb4
-rw-r--r--win32/setup.mak11
-rw-r--r--win32/win32.c277
-rw-r--r--win32/winmain.c4
-rw-r--r--yjit.c227
-rw-r--r--yjit.h24
-rw-r--r--yjit.rb383
-rw-r--r--yjit/Cargo.lock7
-rw-r--r--yjit/Cargo.toml11
-rw-r--r--yjit/bindgen/Cargo.lock163
-rw-r--r--yjit/bindgen/Cargo.toml2
-rw-r--r--yjit/bindgen/src/main.rs66
-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.rs252
-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.rs659
-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.rs596
-rw-r--r--yjit/src/codegen.rs7006
-rw-r--r--yjit/src/core.rs2946
-rw-r--r--yjit/src/cruby.rs107
-rw-r--r--yjit/src/cruby_bindings.inc.rs779
-rw-r--r--yjit/src/disasm.rs138
-rw-r--r--yjit/src/invariants.rs229
-rw-r--r--yjit/src/lib.rs3
-rw-r--r--yjit/src/options.rs187
-rw-r--r--yjit/src/stats.rs500
-rw-r--r--yjit/src/utils.rs41
-rw-r--r--yjit/src/virtualmem.rs107
-rw-r--r--yjit/src/yjit.rs134
-rw-r--r--yjit/yjit.mk46
5802 files changed, 204946 insertions, 361052 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 0000000000..6803edff9b
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,131 @@
+---
+version: '{build}'
+init:
+ - git config --global user.name git
+ - git config --global user.email svn-admin@ruby-lang.org
+ - git config --global core.autocrlf false
+ - git config --global core.eol lf
+ - git config --global advice.detachedHead 0
+shallow_clone: true
+clone_depth: 10
+platform:
+ - x64
+skip_commits:
+ message: /\[DOC\]/
+ files:
+ - doc/*
+ - '**/*.md'
+ - '**/*.rdoc'
+ - '**/.document'
+ - '**/*.[1-8]'
+ - '**/*.ronn'
+environment:
+ 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.
+ # You may test some other stuff on GitHub Actions instead.
+ - build: vs
+ vs: 120
+ ssl: OpenSSL-v111
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GEMS_FOR_TEST: ""
+ RELINE_TEST_ENCODING: "UTF-8"
+cache:
+ - c:\Tools\vcpkg\installed\
+for:
+-
+ matrix:
+ only:
+ - build: vs
+ install:
+ - ver
+ - chcp
+ - SET BITS=%Platform:x86=32%
+ - SET BITS=%BITS:x=%
+ - SET OPENSSL_DIR=C:\%ssl%-Win%BITS%
+ - cd C:\Tools\vcpkg
+ - git pull -q
+ - .\bootstrap-vcpkg.bat
+ - 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
+ - SET vcvars
+ - '"%vcvars%" %Platform:x64=amd64%'
+ - SET ruby_path=C:\Ruby%ruby_version:-x86=%
+ - SET PATH=\usr\local\bin;%ruby_path%\bin;%PATH%;C:\msys64\mingw64\bin;C:\msys64\usr\bin
+ - ruby --version
+ - 'cl'
+ - echo> Makefile srcdir=.
+ - echo>> Makefile MSC_VER=0
+ - echo>> Makefile RT=none
+ - echo>> Makefile RT_VER=0
+ - echo>> Makefile BUILTIN_ENCOBJS=nul
+ - type win32\Makefile.sub >> Makefile
+ - nmake %mflags% up VCSUP="echo Update OK"
+ - nmake %mflags% extract-extlibs
+ - del Makefile
+ - mkdir \usr\local\bin
+ - mkdir \usr\local\include
+ - mkdir \usr\local\lib
+ - for %%I in (%OPENSSL_DIR%\*.dll) do mklink /h \usr\local\bin\%%~nxI %%I
+ - for %%I in (c:\Tools\vcpkg\installed\%Platform%-windows\bin\*.dll) do (
+ if not %%~nI == readline mklink \usr\local\bin\%%~nxI %%I
+ )
+ - attrib +r /s /d
+ - mkdir %Platform%-mswin_%vs%
+ build_script:
+ - cd %APPVEYOR_BUILD_FOLDER%
+ - cd %Platform%-mswin_%vs%
+ - >-
+ ..\win32\configure.bat
+ --with-opt-dir="/usr/local;c:/Tools/vcpkg/installed/%Platform%-windows"
+ --with-openssl-dir=%OPENSSL_DIR:\=/%
+ - nmake -l
+ - nmake install-nodoc
+ - \usr\bin\ruby -v -e "p :locale => Encoding.find('locale'), :filesystem => Encoding.find('filesystem')"
+ - if not "%GEMS_FOR_TEST%" == "" \usr\bin\gem install --no-document %GEMS_FOR_TEST%
+ - \usr\bin\ruby -ropenssl -e "puts 'Build ' + OpenSSL::OPENSSL_VERSION, 'Runtime ' + OpenSSL::OPENSSL_LIBRARY_VERSION"
+ test_script:
+ - set /a JOBS=%NUMBER_OF_PROCESSORS%
+ - nmake -l "TESTOPTS=-v -q" btest
+ - nmake -l "TESTOPTS=-v -q" test-basic
+ - >-
+ nmake -l "TESTOPTS=-v --timeout-scale=3.0
+ --excludes=../test/excludes/_appveyor -j%JOBS%
+ --exclude win32ole
+ --exclude test_bignum
+ --exclude test_syntax
+ --exclude test_open-uri
+ --exclude test_bundled_ca
+ " test-all
+ # separately execute tests without -j which may crash worker with -j.
+ - >-
+ nmake -l
+ "TESTOPTS=-v --timeout-scale=3.0 --excludes=../test/excludes/_appveyor"
+ TESTS="
+ ../test/win32ole
+ ../test/ruby/test_bignum.rb
+ ../test/ruby/test_syntax.rb
+ ../test/open-uri/test_open-uri.rb
+ ../test/rubygems/test_bundled_ca.rb
+ " test-all
+ - nmake -l test-spec MSPECOPT=-fs # not using `-j` because sometimes `mspec -j` silently dies on Windows
+notifications:
+ - provider: Webhook
+ method: POST
+ url:
+ secure: CcFlJNDJ/a6to7u3Z4Fnz6dScEPNx7hTha2GkSRlV+1U6dqmxY/7uBcLXYb9gR3jfQk6w+2o/HrjNAyXMNGU/JOka3s2WRI4VKitzM+lQ08owvJIh0R7LxrGH0J2e81U # ruby-lang slack: ruby/simpler-alerts-bot
+ body: >-
+ {{^isPullRequest}}
+ {
+ "ci": "AppVeyor CI",
+ "env": "Visual Studio 2013",
+ "url": "{{buildUrl}}",
+ "commit": "{{commitId}}",
+ "branch": "{{branch}}"
+ }
+ {{/isPullRequest}}
+ on_build_success: false
+ on_build_failure: true
+ on_build_status_changed: false
diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 0000000000..6c47159921
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,133 @@
+# This CI is used to test Arm cases. We can set the maximum 16 tasks.
+# The entire testing design is inspired from .github/workflows/compilers.yml.
+
+# By default, Cirrus mounts an empty volume to `/tmp`
+# which triggers all sorts of warnings like "system temporary path is world-writable: /tmp".
+# Lets workaround it by specifying a custom volume mount point.
+env:
+ CIRRUS_VOLUME: /cirrus-ci-volume
+ LANG: C.UTF-8
+
+task:
+ name: Arm64 Graviton2 / $CC
+ skip: "changesIncludeOnly('doc/**', '**.{md,rdoc,ronn,[1-8]}', '.document')"
+ arm_container:
+ # We use the arm64 images at https://github.com/ruby/ruby-ci-image/pkgs/container/ruby-ci-image .
+ image: ghcr.io/ruby/ruby-ci-image:$CC
+ # Define the used cpu core in each matrix task. We can use total 16 cpu
+ # cores in entire matrix. [cpu] = [total cpu: 16] / [number of tasks]
+ cpu: 8
+ # We can request maximum 4 GB per cpu.
+ # [memory per task] = [memory per cpu: 4 GB] * [cpu]
+ memory: 32G
+ env:
+ CIRRUS_CLONE_DEPTH: 50
+ optflags: '-O1'
+ debugflags: '-ggdb3'
+ RUBY_PREFIX: /tmp/ruby-prefix
+ RUBY_DEBUG: ci rgengc
+ RUBY_TESTOPTS: >-
+ -q
+ --color=always
+ --tty=no
+ matrix:
+ CC: clang-12
+ CC: gcc-11
+ id_script: id
+ set_env_script:
+ # Set `GNUMAKEFLAGS`, because the flags are GNU make specific. Note using
+ # the `make` environment variable used in compilers.yml causes some rubygems
+ # tests to fail.
+ # https://github.com/rubygems/rubygems/issues/4921
+ - echo "GNUMAKEFLAGS=-s -j$((1 + $CIRRUS_CPU))" >> "$CIRRUS_ENV"
+ - cat "$CIRRUS_ENV"
+ # Arm containers are executed in AWS's EKS, and it's not yet supporting IPv6
+ # See https://github.com/aws/containers-roadmap/issues/835
+ disable_ipv6_script: sudo ./tool/disable_ipv6.sh
+ autogen_script: ./autogen.sh
+ configure_script: >-
+ ./configure -C
+ --enable-debug-env
+ --disable-install-doc
+ --with-ext=-test-/cxxanyargs,+
+ --prefix="$RUBY_PREFIX"
+ make_extract-extlibs_script: make extract-extlibs
+ make_incs_script: make incs
+ make_script: make
+ make_leaked-globals_script: make leaked-globals
+ make_test_script: make test
+ make_install_script: make install
+ install_gems_for_test_script: $RUBY_PREFIX/bin/gem install --no-doc timezone tzinfo
+ make_test-tool_script: make test-tool
+ make_test-all_script: make test-all
+ make_test-spec_script: make test-spec
+
+# The following is to test YJIT on ARM64 CPUs available on Cirrus CI
+yjit_task:
+ name: Arm64 Graviton2 / $CC YJIT
+ auto_cancellation: $CIRRUS_BRANCH != 'master'
+ skip: "changesIncludeOnly('doc/**', '**.{md,rdoc,ronn,[1-8]}', '.document')"
+ arm_container:
+ # We use the arm64 images at https://github.com/ruby/ruby-ci-image/pkgs/container/ruby-ci-image .
+ image: ghcr.io/ruby/ruby-ci-image:$CC
+ # Define the used cpu core in each matrix task. We can use total 16 cpu
+ # cores in entire matrix. [cpu] = [total cpu: 16] / [number of tasks]
+ cpu: 8
+ # We can request maximum 4 GB per cpu.
+ # [memory per task] = [memory per cpu: 4 GB] * [cpu]
+ memory: 32G
+ env:
+ CIRRUS_CLONE_DEPTH: 50
+ optflags: '-O1'
+ debugflags: '-ggdb3'
+ RUBY_PREFIX: /tmp/ruby-prefix
+ RUBY_DEBUG: ci rgengc
+ RUBY_TESTOPTS: >-
+ -q
+ --color=always
+ --tty=no
+ matrix:
+ - CC: clang-12
+ configure: --enable-yjit=dev
+ rustup_init: --default-toolchain=1.58.0
+ - CC: gcc-11
+ configure: --enable-yjit
+ id_script: id
+ set_env_script:
+ # Set `GNUMAKEFLAGS`, because the flags are GNU make specific. Note using
+ # the `make` environment variable used in compilers.yml causes some rubygems
+ # tests to fail.
+ # https://github.com/rubygems/rubygems/issues/4921
+ - echo "GNUMAKEFLAGS=-s -j$((1 + $CIRRUS_CPU))" >> "$CIRRUS_ENV"
+ - echo RUST_BACKTRACE=1 >> "$CIRRUS_ENV"
+ - cat "$CIRRUS_ENV"
+ # Arm containers are executed in AWS's EKS, and it's not yet supporting IPv6
+ # See https://github.com/aws/containers-roadmap/issues/835
+ disable_ipv6_script: sudo ./tool/disable_ipv6.sh
+ install_rust_script:
+ - sudo apt-get update -y
+ - sudo apt-get install -y curl
+ - "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y $rustup_init"
+ autogen_script: ./autogen.sh
+ configure_script: >-
+ source $HOME/.cargo/env && ./configure -C
+ --enable-debug-env
+ --disable-install-doc
+ --with-ext=-test-/cxxanyargs,+
+ --prefix="$RUBY_PREFIX"
+ $configure
+ make_miniruby_script: source $HOME/.cargo/env && make miniruby
+ make_bindgen_script: |
+ if [[ "$CC" = "clang-12" ]]; then
+ source $HOME/.cargo/env && make yjit-bindgen
+ else
+ echo "only running bindgen on clang image"
+ fi
+ boot_miniruby_script: ./miniruby --yjit-call-threshold=1 -e0
+ test_dump_insns_script: ./miniruby --yjit-call-threshold=1 --yjit-dump-insns -e0
+ output_stats_script: ./miniruby --yjit-call-threshold=1 --yjit-stats -e0
+ full_build_script: source $HOME/.cargo/env && make
+ cargo_test_script: source $HOME/.cargo/env && cd yjit && cargo test
+ make_test_script: source $HOME/.cargo/env && make test RUN_OPTS="--yjit-call-threshold=1 --yjit-verify-ctx"
+ make_test_all_script: source $HOME/.cargo/env && make test-all RUN_OPTS="--yjit-call-threshold=1 --yjit-verify-ctx" TESTOPTS="$RUBY_TESTOPTS"
+ make_test_spec_script: source $HOME/.cargo/env && make test-spec RUN_OPTS="--yjit-call-threshold=1 --yjit-verify-ctx"
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 4150288ed7..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@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.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
index 8726df577d..d058b6ca00 100644
--- a/.github/auto_request_review.yml
+++ b/.github/auto_request_review.yml
@@ -1,13 +1,9 @@
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]
+ '.github/workflows/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 25454f6abe..0000000000
--- a/.github/workflows/annocheck.yml
+++ /dev/null
@@ -1,127 +0,0 @@
-name: Annocheck
-
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
-
-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
- continue-on-error: true # toomanyrequests: You have reached your pull rate limit.
-
- - 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
index 998a6ea58a..340aae4391 100644
--- a/.github/workflows/auto_request_review.yml
+++ b/.github/workflows/auto_request_review.yml
@@ -10,10 +10,10 @@ jobs:
auto-request-review:
name: Auto Request Review
runs-on: ubuntu-latest
- if: ${{ github.repository == 'ruby/ruby' && github.base_ref == 'master' }}
+ 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
+ uses: necojackarc/auto-request-review@5f91f424cabb3211c669e49e79da8363f7df395b # v0.10.0
with:
# scope: public_repo
token: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml
index 860d74aa1a..2709800ef1 100644
--- a/.github/workflows/baseruby.yml
+++ b/.github/workflows/baseruby.yml
@@ -8,7 +8,6 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
@@ -16,15 +15,6 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -36,49 +26,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]')
- )}}
-
+ 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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
+ with:
+ path: .downloaded-cache
+ key: downloaded-cache
+ - uses: ruby/setup-ruby@4b2d1d631efa087f8896c15a0c6023dc2f483198 # v1.128.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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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..80b1c5466c 100644
--- a/.github/workflows/bundled_gems.yml
+++ b/.github/workflows/bundled_gems.yml
@@ -2,17 +2,10 @@ name: bundled_gems
on:
push:
- branches: ['master']
paths:
- '.github/workflows/bundled_gems.yml'
- 'gems/bundled_gems'
pull_request:
- branches: ['master']
- paths:
- - '.github/workflows/bundled_gems.yml'
- - 'gems/bundled_gems'
- merge_group:
- branches: ['master']
paths:
- '.github/workflows/bundled_gems.yml'
- 'gems/bundled_gems'
@@ -20,34 +13,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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
+
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
+ 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 +51,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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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 37b9935146..6aaf3c9a4e 100644
--- a/.github/workflows/check_dependencies.yml
+++ b/.github/workflows/check_dependencies.yml
@@ -7,7 +7,6 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
@@ -15,15 +14,6 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -34,45 +24,49 @@ permissions:
jobs:
update-deps:
- name: Dependency checks
-
strategy:
matrix:
- os: [ubuntu-latest]
+ os: [ubuntu-20.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 upgrade
+ 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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
+ 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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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 ce4397b35a..0000000000
--- a/.github/workflows/check_misc.yml
+++ /dev/null
@@ -1,117 +0,0 @@
-name: Misc
-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:
- name: Miscellaneous 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/cirrus-notify.yml b/.github/workflows/cirrus-notify.yml
new file mode 100644
index 0000000000..bd99a71ecd
--- /dev/null
+++ b/.github/workflows/cirrus-notify.yml
@@ -0,0 +1,46 @@
+on:
+ check_suite:
+ type: ['completed']
+name: Cirrus CI failure notification
+
+permissions:
+ contents: read
+
+jobs:
+ cirrus-notify:
+ name: After Cirrus CI Failure
+ if: >-
+ github.event.check_suite.app.name == 'Cirrus CI'
+ && github.event.check_suite.conclusion != 'success'
+ && github.event.check_suite.conclusion != 'cancelled'
+ && github.event.check_suite.conclusion != 'skipped'
+ && github.event.check_suite.head_branch == 'master'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: octokit/request-action@8cd8f5d6738d122de9213dc5cf87e116c40f5fae # v2.x
+ id: get_failed_check_run
+ with:
+ route: GET /repos/${{ github.repository }}/check-suites/${{ github.event.check_suite.id }}/check-runs?status=completed
+ mediaType: '{"previews": ["antiope"]}'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Dump GitHub context
+ env:
+ GITHUB_CONTEXT: ${{ toJson(github) }}
+ run: echo "$GITHUB_CONTEXT"
+ - name: Dump check_runs
+ env:
+ CHECK_RUNS: ${{ steps.get_failed_check_run.outputs.data }}
+ run: echo "$CHECK_RUNS"
+ - uses: ruby/action-slack@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
+ with:
+ payload: |
+ {
+ "ci": "Cirrus CI",
+ "env": "Cirrus CI",
+ "url": "${{ fromJson(steps.get_failed_check_run.outputs.data).check_runs[0].html_url }}",
+ "commit": "${{ github.event.check_suite.head_commit.id }}",
+ "branch": "${{ github.event.check_suite.head_branch }}"
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 47104672fe..b86bec4224 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -1,23 +1,20 @@
-name: 'CodeQL'
+name: "Code scanning - action"
on:
- push:
- branches: ['master']
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
+ # push:
+ # paths-ignore:
+ # - 'doc/**'
+ # - '**/man'
+ # - '**.md'
+ # - '**.rdoc'
+ # - '**/.document'
+ # pull_request:
+ # paths-ignore:
+ # - 'doc/**'
+ # - '**/man'
+ # - '**.md'
+ # - '**.rdoc'
+ # - '**/.document'
schedule:
- cron: '0 12 * * *'
workflow_dispatch:
@@ -26,90 +23,52 @@ 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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
- - name: Remove an obsolete rubygems vendored file
- run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
+ 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
- - 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' }}
- continue-on-error: true
+ - 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
- continue-on-error: true
+ - 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 c00674c410..4f04141138 100644
--- a/.github/workflows/compilers.yml
+++ b/.github/workflows/compilers.yml
@@ -1,4 +1,3 @@
-# Some tests depending on this name 'Compilations' via $GITHUB_WORKFLOW. Make sure to update such tests when renaming this workflow.
name: Compilations
on:
@@ -9,23 +8,12 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
- '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -35,7 +23,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
@@ -56,8 +44,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
@@ -75,22 +68,33 @@ 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 } }
- { name: gcc-9, env: { default_cc: gcc-9 } }
- { name: gcc-8, env: { default_cc: gcc-8 } }
- { name: gcc-7, env: { default_cc: gcc-7 } }
- - name: 'gcc-13 LTO'
- container: gcc-13
+ - { name: gcc-6, env: { default_cc: gcc-6 } }
+ - { name: gcc-5, env: { default_cc: gcc-5 } }
+ - { name: gcc-4.8, env: { default_cc: gcc-4.8 } }
+ - name: 'gcc-11 LTO'
+ container: gcc-11
env:
- default_cc: 'gcc-13 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch'
+ default_cc: 'gcc-11 -flto=auto -ffat-lto-objects'
optflags: '-O2'
shared: disable
# check: true
- - { name: clang-18, env: { default_cc: clang-18 } }
- - { name: clang-17, env: { default_cc: clang-17 } }
+ - name: 'gcc-11 annocheck'
+ container: gcc-11
+ env:
+ # Minimal flags to pass the check.
+ default_cc: 'gcc-11 -O2 -fcf-protection -Wa,--generate-missing-build-notes=yes'
+ LDFLAGS: '-Wl,-z,now'
+ # 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"
+ check: true
- { name: clang-16, env: { default_cc: clang-16 } }
- { name: clang-15, env: { default_cc: clang-15 } }
- { name: clang-14, env: { default_cc: clang-14 } }
@@ -98,21 +102,21 @@ jobs:
- { name: clang-12, env: { default_cc: clang-12 } }
- { name: clang-11, env: { default_cc: clang-11 } }
- { name: clang-10, env: { default_cc: clang-10 } }
- # llvm-objcopy<=9 doesn't have --wildcard. It compiles, but leaves Rust symbols in libyjit.o.
- - { name: clang-9, env: { default_cc: clang-9, append_configure: '--disable-yjit' } }
- - { name: clang-8, env: { default_cc: clang-8, append_configure: '--disable-yjit' } }
- - { name: clang-7, env: { default_cc: clang-7, append_configure: '--disable-yjit' } }
- - { name: clang-6.0, env: { default_cc: clang-6.0, append_configure: '--disable-yjit' } }
- - name: 'clang-16 LTO'
- container: clang-16
+ - { name: clang-9, env: { default_cc: clang-9 } }
+ - { name: clang-8, env: { default_cc: clang-8 } }
+ - { name: clang-7, env: { default_cc: clang-7 } }
+ - { name: clang-6.0, env: { default_cc: clang-6.0 } }
+ - { name: clang-5.0, env: { default_cc: clang-5.0 } }
+ - { name: clang-4.0, env: { default_cc: clang-4.0 } }
+ - { name: clang-3.9, env: { default_cc: clang-3.9 } }
+ - name: 'clang-14 LTO'
+ container: clang-14
env:
- default_cc: 'clang-16 -flto=auto'
+ default_cc: 'clang-14 -flto=auto'
optflags: '-O2'
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 }
@@ -128,27 +132,25 @@ 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 }
- - { name: gmp, env: { append_configure: '--with-gmp' }, check: 'ruby/test_bignum.rb' }
+ - { name: gmp, env: { append_configure: '--with-gmp' } }
- { name: jemalloc, env: { append_configure: '--with-jemalloc' } }
- { 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' } }
@@ -172,27 +174,27 @@ 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
- env:
- cppflags: '-DUSE_FLONUM=0'
- # yjit requires FLONUM for the pointer tagging scheme
- append_configure: '--disable-yjit'
+ - { name: USE_EMBED_CI=0, env: { cppflags: '-DUSE_EMBED_CI=0' } }
+ - { name: USE_FLONUM=0, env: { cppflags: '-DUSE_FLONUM=0' } }
# - { 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' } }
@@ -205,50 +207,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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - run: mkdir build
+ working-directory:
+ - name: setenv
+ run: |
+ echo "GNUMAKEFLAGS=-sj$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
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}
@@ -258,41 +249,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="-- $tests"
+ - run: make test-all TESTS='-- ruby -ext-'
if: ${{ matrix.entry.check }}
- env:
- tests: ${{ matrix.entry.check == true && 'ruby -ext-' || 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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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 fc98b09f5f..329631e2f6 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -7,18 +7,13 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
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'
- - '.*.yml'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -31,86 +26,80 @@ jobs:
make:
strategy:
matrix:
- test_task: ['check']
- configure: ['']
- os: ['macos-13', 'macos-14']
- include:
- - test_task: test-all TESTS=--repeat-count=2
- os: macos-14
+ test_task: ["check"] # "test-bundler-parallel", "test-bundled-gems"
+ os:
+ - macos-11
+ - macos-12
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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
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@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
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 upgrade
+ 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:$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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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 df879f56b6..4d0430459a 100644
--- a/.github/workflows/mingw.yml
+++ b/.github/workflows/mingw.yml
@@ -7,8 +7,6 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
@@ -16,17 +14,6 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
- - '.*.yml'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- - '.*.yml'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -41,42 +28,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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
+ with:
+ path: src
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
+ 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@4b2d1d631efa087f8896c15a0c6023dc2f483198 # v1.128.0
with:
ruby-version: ${{ matrix.base_ruby }}
+ - name: set env
+ run: |
+ echo "GNUMAKEFLAGS=-j$((2 * NUMBER_OF_PROCESSORS))" >> $GITHUB_ENV
- name: where check
run: |
@@ -84,83 +79,92 @@ 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
- shell: cmd
- 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
- shell: cmd
run: |
+ # Actions uses UTF8, causes test failures, similar to normal OS setup
+ chcp.com 437
make ${{ StartsWith(matrix.test_task, 'test/') && matrix.test_task || 'test-all' }}
env:
RUBY_TESTOPTS: >-
--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' }}
- shell: cmd
- 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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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..a8d85e030c
--- /dev/null
+++ b/.github/workflows/mjit-bindgen.yml
@@ -0,0 +1,97 @@
+name: MJIT bindgen
+on:
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ pull_request:
+ 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-20.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-10 \
+ bison autoconf
+ sudo apt-get install -q -y pkg-config || :
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@4b2d1d631efa087f8896c15a0c6023dc2f483198 # v1.128.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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
+ with:
+ path: src
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
+ 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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
+ 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..34c971bdee
--- /dev/null
+++ b/.github/workflows/mjit.yml
@@ -0,0 +1,103 @@
+name: MJIT
+on:
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ pull_request:
+ 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:
+ 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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
+ with:
+ path: src
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
+ 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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
+ 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
deleted file mode 100644
index 5d4474d978..0000000000
--- a/.github/workflows/publish.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-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 bf3c752e7b..0000000000
--- a/.github/workflows/rjit-bindgen.yml
+++ /dev/null
@@ -1,91 +0,0 @@
-name: RJIT bindgen
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
-
-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 bf9122f581..0000000000
--- a/.github/workflows/rjit.yml
+++ /dev/null
@@ -1,120 +0,0 @@
-name: RJIT
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '**.[1-8]'
- - '**.ronn'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '**.[1-8]'
- - '**.ronn'
- - '.*.yml'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '**.[1-8]'
- - '**.ronn'
- - '.*.yml'
-
-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..5e2397e693 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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
with:
persist-credentials: false
- - name: 'Run analysis'
- uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2
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@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1
+ 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..4c20610ac6 100644
--- a/.github/workflows/spec_guards.yml
+++ b/.github/workflows/spec_guards.yml
@@ -9,10 +9,6 @@ on:
paths-ignore:
- 'spec/**'
- '!spec/*.md'
- merge_group:
- paths-ignore:
- - 'spec/**'
- - '!spec/*.md'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -24,43 +20,37 @@ permissions:
jobs:
rubyspec:
name: Rubyspec
-
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]')
- )}}
-
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
strategy:
matrix:
# 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-2.7
- ruby-3.1
- - ruby-3.2
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
-
- - uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0
+ - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
+ - uses: ruby/setup-ruby@4b2d1d631efa087f8896c15a0c6023dc2f483198 # v1.128.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
-
- run: gem install webrick
-
- run: ruby ../mspec/bin/mspec
working-directory: spec/ruby
env:
CHECK_LEAKS: true
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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() }}
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index 93ced0d1d2..60e5ce13e3 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -7,18 +7,13 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
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'
- - '.*.yml'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -31,101 +26,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-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
-
+ SETARCH: ${{ matrix.arch && format('setarch {0}', matrix.arch) }}
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]')
- )}}
-
+ 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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
with:
- arch: ${{ matrix.arch }}
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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 543b7d963c..172dd3791b 100644
--- a/.github/workflows/wasm.yml
+++ b/.github/workflows/wasm.yml
@@ -7,7 +7,6 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
@@ -15,21 +14,12 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
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:
@@ -38,50 +28,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 }}
- WASI_SDK_VERSION_MAJOR: 20
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ WASI_SDK_VERSION_MAJOR: 14
WASI_SDK_VERSION_MINOR: 0
- BINARYEN_VERSION: 113
- WASMTIME_VERSION: v15.0.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]')
- )}}
-
+ 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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
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}"
@@ -100,27 +78,17 @@ 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
-
- - name: Build baseruby
- run: |
- set -ex
- mkdir ../baseruby
- pushd ../baseruby
- ../src/configure --prefix=$PWD/install
- make
- make install
-
+ - run: ./autogen.sh
+ working-directory: src
- name: Run configure
run: |
../src/configure \
--host wasm32-unknown-wasi \
- --with-baseruby=$PWD/../baseruby/install/bin/ruby \
--with-static-linked-ext \
- --with-ext=bigdecimal,cgi/escape,continuation,coverage,date,dbm,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,fiber,gdbm,json,json/generator,json/parser,nkf,objspace,pathname,racc/cparse,rbconfig/sizeof,ripper,stringio,strscan,monitor \
LDFLAGS=" \
-Xlinker --stack-first \
-Xlinker -z -Xlinker stack-size=16777216 \
@@ -131,31 +99,28 @@ jobs:
# miniruby may not be built when cross-compling
- run: make mini ruby
-
- - run: make install DESTDIR=$PWD/../install
- - run: tar cfz ../install.tar.gz -C ../install .
-
- - name: Upload artifacts
- uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1
- with:
- name: ruby-wasm-install
- path: ${{ github.workspace }}/install.tar.gz
-
- 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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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 cdbaf88c58..f10e9bd6b6 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -7,7 +7,6 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
@@ -15,15 +14,6 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
- merge_group:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -38,173 +28,130 @@ jobs:
matrix:
include:
- vs: 2019
- # - vs: 2022
+ - vs: 2022
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]')
- )}}
-
+ 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 }}
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ PATCH: C:\msys64\usr\bin\patch.exe
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
-
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
id: setup-msys2
with:
update: true
install: >-
- ${{ steps.find-tools.outputs.needs }}
- if: ${{ steps.find-tools.outputs.needs != '' }}
-
- - uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
+ patch
+ if: ${{ env.OS_VER != 'windows-2019' }}
+ - 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@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
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@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
with:
path: C:\vcpkg\installed
- key: ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-${{ github.sha }}
+ key: ${{ runner.os }}-vcpkg-installed-${{ matrix.os }}-${{ github.sha }}
restore-keys: |
- ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-
+ ${{ runner.os }}-vcpkg-installed-${{ matrix.os }}-
${{ runner.os }}-vcpkg-installed-
-
- name: Install libraries with vcpkg
run: |
vcpkg --triplet x64-windows install libffi libyaml openssl readline zlib
-
- - name: Install libraries with scoop
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
+ with:
+ path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
+ key: ${{ runner.os }}-chocolatey-${{ env.OS_VER }}-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-chocolatey-${{ env.OS_VER }}-
+ ${{ runner.os }}-chocolatey-
+ - name: Install libraries with chocolatey
run: |
- iex "& {$(irm get.scoop.sh)} -RunAsAdmin"
- Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH
- scoop install vcpkg cmake@3.31.6
+ # Using Choco-Install for retries, but it doesn't detect failures properly
+ # if you pass multiple package names in a single command.
+ Choco-Install -PackageName winflexbison3
shell: pwsh
-
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - 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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
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
run: |
set VS=${{ matrix.vs }}
- set VCVARS=${{ matrix.vcvars || '' }}
+ set VCVARS=${{ matrix.vcvars }}
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"
:vcset
set | C:\msys64\usr\bin\sort > old.env
call %VCVARS%
- nmake -f nul
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: win_bison
- 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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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() }}
-
- result:
- if: ${{ always() }}
- name: ${{ github.workflow }} result
- runs-on: windows-latest
- needs: [make]
- steps:
- - run: exit 1
- working-directory:
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ 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 49fff17ae9..0000000000
--- a/.github/workflows/yjit-macos.yml
+++ /dev/null
@@ -1,151 +0,0 @@
-name: YJIT macOS Arm64
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- 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'
- - '.*.yml'
-
-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-14
-
- 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-14
-
- 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-14
- 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 ec8483b7d1..4677822b33 100644
--- a/.github/workflows/yjit-ubuntu.yml
+++ b/.github/workflows/yjit-ubuntu.yml
@@ -7,18 +7,13 @@ on:
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
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'
- - '.*.yml'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -29,173 +24,137 @@ 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]')
- )}}
-
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
-
+ - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
# 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
matrix:
include:
- - test_task: 'yjit-bindgen'
- hint: 'To fix: use patch in logs'
- configure: '--with-gcc=clang-12 --enable-yjit=dev'
+ - test_task: "yjit-bindgen"
+ hint: "To fix: use patch in logs"
+ configure: "--with-gcc=clang-12 --enable-yjit=dev"
- - 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]')
- )}}
-
+ 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@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
+ with:
+ path: src
+ - uses: actions/cache@c17f4bf4666a8001b1a45c09eb7a485c41aa64c3 # v3.2.0
+ 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"
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@b6882ea6ef8f556f9f9af9ec1220d3f1ced74acf # v3.0.0
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 b6beba3b3e..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
@@ -138,7 +136,6 @@ lcov*.info
/test.rb
/test-coverage.dat
/tmp
-/vcpkg_installed
/transdb.h
/uncommon.mk
/verconf.h
@@ -167,7 +164,6 @@ lcov*.info
# /coroutine/
!/coroutine/**/*.s
-!/coroutine/**/*.S
# /enc/trans/
/enc/trans/*.c
@@ -207,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
@@ -232,9 +226,8 @@ lcov*.info
# /misc/
/misc/**/__pycache__
-# for `make test-bundler`
+# /spec/bundler
/.rspec_status
-/tool/bundler/*.lock
# /tool/
/tool/config.guess
@@ -243,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
@@ -256,28 +248,3 @@ lcov*.info
# /wasm/
/wasm/tests/*.wasm
-
-# prism
-/lib/prism/compiler.rb
-/lib/prism/dispatcher.rb
-/lib/prism/dot_visitor.rb
-/lib/prism/dsl.rb
-/lib/prism/inspect_visitor.rb
-/lib/prism/mutation_compiler.rb
-/lib/prism/node.rb
-/lib/prism/reflection.rb
-/lib/prism/serialize.rb
-/lib/prism/visitor.rb
-/prism/api_node.c
-/prism/ast.h
-/prism/diagnostic.c
-/prism/diagnostic.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
index 2ac2372584..665feba914 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,46 +6,63 @@
# 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 OR branch = master OR branch =~ /^ruby_\d_\d$/)
- AND (commit_message !~ /\[DOC\]/)
+# We only manage non-amd64 free pipelines.
+# https://docs.travis-ci.com/user/billing-overview/
language: c
os: linux
-dist: jammy
+if: commit_message !~ /\[DOC\]/
+
+dist: focal
git:
quiet: true
+cache:
+ ccache: true
+ directories:
+ - $HOME/config_2nd
+ - $HOME/.downloaded-cache
+
env:
global:
- - NPROC="$(nproc)"
- - JOBS="-j${NPROC}"
- # SETARCH are overridden when necessary. See below.
+ # The tests skipped in `make test-all`.
+ - TEST_ALL_SKIPPED_TESTS=
+ # The tests executed separately by `make test-all`.
+ - TEST_ALL_SEPARATED_TESTS=
+ # Reset timestamps early
+ - _=$(touch NEWS && find . -type f -exec touch -r NEWS {} +)
+ - CONFIGURE_TTY=no
+ - CCACHE_COMPILERCHECK=none
+ - CCACHE_NOCOMPRESS=1
+ - CCACHE_MAXSIZE=512Mi
+ - NPROC="`nproc`"
+ # JOBS and SETARCH are overridden when necessary; see below.
+ - JOBS=-j$((1+${NPROC}))
- SETARCH=
+ - RUBY_PREFIX=/tmp/ruby-prefix
+ - GEMS_FOR_TEST='timezone tzinfo'
# 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.
+ # -O1 is faster than -O3 in our tests.
+ - optflags=-O1
+ # -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
+
+ - &gcc-10
+ compiler: gcc-10
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
+ ccache
+ gcc-10
+ g++-10
libffi-dev
libncurses-dev
libncursesw5-dev
@@ -54,42 +71,40 @@ env:
libyaml-dev
openssl
zlib1g-dev
- - gcc-11 --version
+
+ # --------
+
- &arm64-linux
name: arm64-linux
arch: arm64
- <<: *gcc-11
+ <<: *gcc-10
+
- &ppc64le-linux
name: ppc64le-linux
arch: ppc64le
- <<: *gcc-11
+ <<: *gcc-10
+
- &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
+ <<: *gcc-10
+
- &arm32-linux
name: arm32-linux
arch: arm64
- # https://packages.ubuntu.com/jammy/crossbuild-essential-armhf
+ # https://packages.ubuntu.com/focal/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
+ # The "TestReadline#test_interrupt_in_other_thread" started failing on arm32
+ # from https://www.travis-ci.com/github/ruby/ruby/jobs/529005145
+ - TEST_ALL_SKIPPED_TESTS=test_interrupt_in_other_thread
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
+ ccache
crossbuild-essential-armhf
libc6:armhf
libstdc++-10-dev:armhf
@@ -104,48 +119,117 @@ env:
matrix:
include:
- - <<: *arm64-linux
+ # Build every commit (Allowed Failures):
+ - <<: *arm32-linux
+ # Comment out as the 2nd arm64 pipeline is unstable.
+ # - <<: *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
+ # We see multiple errors indicating errors on the Travis environment itself in a short while:
+ # https://app.travis-ci.com/github/ruby/ruby/jobs/544382885
+ # https://app.travis-ci.com/github/ruby/ruby/jobs/544361370
+ # It's not a fault of Ruby's arm32 support but just Travis arm32 seems unsable.
+ - name: arm32-linux
+ # - name: arm64-linux
+ # We see "Some worker was crashed." in about 40% of recent ppc64le-linux jobs
+ # e.g. https://app.travis-ci.com/github/ruby/ruby/jobs/530959548
- name: ppc64le-linux
+ # Tentatively disable, because often hungs up **after** all tests
+ # have finished successfully and saving caches.
- name: s390x-linux
- - name: arm32-linux
fast_finish: true
before_script:
- - ./autogen.sh
- - mkdir build
+ - . tool/ci_functions.sh
+ - |-
+ if [ -n "${TEST_ALL_SKIPPED_TESTS}" ]; then
+ TEST_ALL_OPTS="${TEST_ALL_OPTS} $(ci_to_excluded_test_opts "${TEST_ALL_SKIPPED_TESTS}")"
+ if [ -z "${TEST_ALL_SEPARATED_TESTS}" ]; then
+ TEST_ALL_SEPARATED_TESTS="${TEST_ALL_SKIPPED_TESTS}"
+ fi
+ fi
+ - |-
+ if [ -n "${TEST_ALL_SEPARATED_TESTS}" ]; then
+ TEST_ALL_OPTS_SEPARATED="$(ci_to_included_test_opts "${TEST_ALL_SEPARATED_TESTS}")"
+ fi
+ - echo TEST_ALL_OPTS="${TEST_ALL_OPTS}" TEST_ALL_OPTS_SEPARATED="${TEST_ALL_OPTS_SEPARATED}"
+ - rm -fr .ext autom4te.cache
+ - |-
+ [ -d ~/.downloaded-cache ] ||
+ mkdir ~/.downloaded-cache
+ - ln -s ~/.downloaded-cache
+ - "> config.status"
+ - "> .rbconfig.time"
+ - sed -f tool/prereq.status template/Makefile.in common.mk > Makefile
+ - make -s $JOBS up
+ - make -s $JOBS srcs
+ - rm -f config.status Makefile rbconfig.rb .rbconfig.time
+ - |-
+ if [ -d ~/config_2nd ]; then
+ cp -pr ~/config_2nd build
+ else
+ mkdir build
+ fi
+ - mkdir config_1st config_2nd gems/src
+ - chmod -R a-w .
+ - chmod -R u+w build config_1st config_2nd gems/src
- cd build
- - $SETARCH ../configure -C --disable-install-doc --prefix=$(pwd)/install
+ - |-
+ case "$CC" in
+ gcc*) CC="ccache $CC${GCC_FLAGS:+ }$GCC_FLAGS -fno-diagnostics-color";;
+ clang*) CC="ccache $CC${GCC_FLAGS:+ }$GCC_FLAGS -fno-color-diagnostics";;
+ esac
+ - |-
+ [ ! -f config.cache ] ||
+ [ "$CC" = "`sed -n s/^ac_cv_prog_CC=//p config.cache`" ] ||
+ (set -x; exec rm config.cache)
+ - $SETARCH ../configure -C --disable-install-doc --prefix=$RUBY_PREFIX $CONFIG_FLAG
+ - cp -pr config.cache config.status .ext/include ../config_1st
+ - $SETARCH make reconfig
+ - cp -pr config.cache config.status .ext/include ../config_2nd
+ - (cd .. && exec diff -ru config_1st config_2nd)
+ - chmod u+w ..
+ - rm -rf ~/config_2nd
+ - mv ../config_2nd ~
+ - chmod u-w ..
- $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
+ - make -s install
+ - |-
+ [ -z "${GEMS_FOR_TEST}" ] ||
+ $RUBY_PREFIX/bin/gem install --no-document $GEMS_FOR_TEST
+ - echo "raise 'do not load ~/.irbrc in test'" > ~/.irbrc
script:
- - $SETARCH make -s test
- - ../tool/travis_wait.sh $SETARCH make -s test-all RUBYOPT="-w"
- - $SETARCH make -s test-spec
+ - $SETARCH make -s test -o showflags TESTOPTS="${TESTOPTS=$JOBS -q --tty=no}"
+ - ../tool/travis_wait.sh $SETARCH make -s test-all -o exts TESTOPTS="$JOBS -q --tty=no ${TEST_ALL_OPTS}" RUBYOPT="-w"
+ # Run the failing tests separately returning ok status to check if it works,
+ # visualize them.
+ - |
+ if [ -n "${TEST_ALL_OPTS_SEPARATED}" ]; then
+ $SETARCH make -s test-all -o exts TESTOPTS="$JOBS -v --tty=no ${TEST_ALL_OPTS_SEPARATED}" RUBYOPT="-w" || :
+ fi
+ - $SETARCH make -s test-spec MSPECOPT=-ff # not using `-j` because sometimes `mspec -j` silently dies
+ - $SETARCH make -s -o showflags leaked-globals
+
+# 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
# We want to be notified when something happens.
notifications:
+ irc:
+ channels:
+ - "chat.freenode.net#ruby-core"
+ on_success: change # [always|never|change] # default: always
+ on_failure: always # [always|never|change] # default: always
+ template:
+ - "%{message} by @%{author}: See %{build_url}"
+
webhooks:
urls:
- # ruby-lang slack: ruby/simpler-alerts-bot (travis)
- - secure: mRsoS/UbqDkKkW5p3AEqM27d4SZnV6Gsylo3bm8T/deltQzTsGzZwrm7OIBXZv0UFZdE68XmPlyHfZFLSP2V9QZ7apXMf9/vw0GtcSe1gchtnjpAPF6lYBn7nMCbVPPx9cS0dwL927fjdRM1vj7IKZ2bk4F0lAJ25R25S6teqdk=
+ - secure: mRsoS/UbqDkKkW5p3AEqM27d4SZnV6Gsylo3bm8T/deltQzTsGzZwrm7OIBXZv0UFZdE68XmPlyHfZFLSP2V9QZ7apXMf9/vw0GtcSe1gchtnjpAPF6lYBn7nMCbVPPx9cS0dwL927fjdRM1vj7IKZ2bk4F0lAJ25R25S6teqdk= # ruby-lang slack: ruby/simpler-alerts-bot (travis)
on_success: never
on_failure: always
+
email:
- recipients:
- - jaruga@ruby-lang.org
- on_success: never
- on_failure: always
+ - 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 364786d754..33a7b85c47 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,529 +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.
-## Command line options
+## Language changes
-* 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]]
+* Anonymous rest and keyword rest arguments can now be passed as
+ arguments, instead of just used in method parameters.
+ [[Feature #18351]]
-* A new `RUBY_CRASH_REPORT` environment variable was introduced to allow
- redirecting Ruby crash reports to a file or sub command. See the `BUG REPORT ENVIRONMENT`
- section of the ruby manpage for further details. [[Feature #19790]]
+ ```ruby
+ def foo(*)
+ bar(*)
+ end
+ def baz(**)
+ quux(**)
+ end
+ ```
-## Core classes updates
+* A proc that accepts a single positional argument and keywords will
+ no longer autosplat. [[Bug #18633]]
-Note: We're only listing outstanding class updates.
+ ```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
+ ```
-* Array
+ The following evaluation order is now used:
- * Array#pack now raises ArgumentError for unknown directives. [[Bug #19150]]
+ 1. `foo1`
+ 2. `foo2`
+ 3. `baz1`
+ 4. `baz2`
-* Dir
+ [[Bug #15928]]
- * 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]]
+* "Find pattern" is no longer experimental.
+ [[Feature #18585]]
-* Encoding
+* 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
- * `Encoding#replicate` has been removed, it was already deprecated. [[Feature #18949]]
+Note: We're only listing outstanding class updates.
* Fiber
- * Introduce Fiber#kill. [[Bug #595]]
+ * 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
- fiber = Fiber.new do
- while true
- puts "Yielding..."
- Fiber.yield
+ 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
- ensure
- puts "Exiting..."
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
- fiber.resume
- # Yielding...
- fiber.kill
- # Exiting...
+ * 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)
```
-* MatchData
+ * Introduce `IO.new(..., path:)` and promote `File#path` to `IO#path`.
+ [[Feature #19036]]
- * MatchData#named_captures now accepts optional `symbolize_names`
- keyword. [[Feature #19591]]
+* Class
-* Module
+ * 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]]
- * Module#set_temporary_name added for setting a temporary name for a
- module. [[Feature #19521]]
+* Enumerator
-* ObjectSpace::WeakKeyMap
+ * Enumerator.product has been added. Enumerator::Product is the implementation. [[Feature #18685]]
- * 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]]
+* Exception
-* ObjectSpace::WeakMap
+ * Exception#detailed_message has been added.
+ The default error printer calls this method on the Exception object
+ instead of #message. [[Feature #18564]]
- * ObjectSpace::WeakMap#delete was added to eagerly clear weak map
- entries. [[Feature #19561]]
+* 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
- * Now Proc#dup and Proc#clone call `#initialize_dup` and `#initialize_clone`
- hooks respectively. [[Feature #19362]]
+
+ * 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
- * New Process.warmup method that 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]]
+* Regexp
-* Process::Status
+ * 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]]
- * Process::Status#& and Process::Status#>> are deprecated. [[Bug #19868]]
+ * Regexp.linear_time? is introduced. [[Feature #19194]]
-* Range
+ * 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]]
- * Range#reverse_each can now process beginless ranges with an Integer endpoint. [[Feature #18515]]
- * Range#reverse_each now raises TypeError for endless ranges. [[Feature #18551]]
- * Range#overlap? added for checking if two ranges overlap. [[Feature #19839]]
+ * 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]]
-* Regexp
+* 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
- * The cache-based optimization now supports lookarounds and atomic groupings. That is, match
- for Regexp containing these extensions can now also be performed in linear time to the length
- of the input string. However, these cannot contain captures and cannot be nested. [[Feature #19725]]
+ ```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#freeze now raises TypeError. [[Bug #17146]]
+ * Thread::Queue#pop(timeout: sec) is added. [[Feature #18774]]
* Thread::SizedQueue
- * Thread::SizedQueue#freeze now raises TypeError. [[Bug #17146]]
+ * Thread::SizedQueue#pop(timeout: sec) is added. [[Feature #18774]]
+ * Thread::SizedQueue#push(timeout: sec) is added. [[Feature #18944]]
* Time
- * Time.new with a string argument became stricter. [[Bug #19293]]
+ * Time#deconstruct_keys is added, allowing to use Time instances
+ in pattern-matching expressions [[Feature #19071]]
- ```ruby
- Time.new('2023-12-20')
- # no time information (ArgumentError)
- ```
+ * 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 do `require` the following gems without adding them to Gemfile or gemspec.
- This is because they will become the bundled gems in the future version of Ruby. This warning is suppressed
- if you use bootsnap gem. We recommend to run your application with `DISABLE_BOOTSNAP=1` environmental variable
- at least once. This is limitation of this version.
- [[Feature #19351]] [[Feature #19776]] [[Feature #19843]]
- * 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]]
-
-* Name resolution such as Socket.getaddrinfo, Socket.getnameinfo, Addrinfo.getaddrinfo, etc.
- can now be interrupted. [[Feature #19965]]
-
-* Random::Formatter#alphanumeric is extended to accept optional `chars`
- keyword argument. [[Feature #18183]]
-
-The following default gem is added.
-
-* prism 0.19.0
-
-The following default gems are updated.
-
-* RubyGems 3.5.3
-* abbrev 0.1.2
-* base64 0.2.0
-* benchmark 0.3.0
-* bigdecimal 3.1.5
-* bundler 2.5.3
-* cgi 0.4.1
-* csv 3.2.8
-* date 3.3.4
-* delegate 0.3.1
-* drb 2.2.0
-* english 0.8.0
-* erb 4.0.3
-* error_highlight 0.6.0
-* etc 1.4.3
-* fcntl 1.1.0
-* fiddle 1.1.2
-* fileutils 1.7.2
-* find 0.2.0
-* getoptlong 0.2.1
-* io-console 0.7.1
-* io-nonblock 0.3.0
-* io-wait 0.3.1
-* ipaddr 1.2.6
-* irb 1.11.0
-* json 2.7.1
-* 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.1
-* open3 0.2.1
-* 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.2
-* rdoc 6.6.2
-* readline 0.0.4
-* reline 0.4.1
-* resolv 0.3.0
-* rinda 0.2.0
-* securerandom 0.3.1
-* set 1.1.0
-* shellwords 0.2.0
-* singleton 0.2.0
-* stringio 3.1.0
-* strscan 3.0.7
-* syntax_suggest 2.0.0
-* syslog 0.1.2
-* tempfile 0.2.1
-* 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-ftp 0.3.3
-* net-imap 0.4.9
-* net-smtp 0.4.0
-* rbs 3.4.0
-* typeprof 0.21.9
-* debug 1.9.1
-
-See GitHub releases like [Logger](https://github.com/ruby/logger/releases) or
-changelog for details of the default gems or bundled gems.
-
-### Prism
-
-* Introduced [the Prism parser](https://github.com/ruby/prism) as a default gem
- * Prism is a portable, error tolerant, and maintainable recursive descent parser for the Ruby language
-* Prism is production ready and actively maintained, you can use it in place of Ripper
- * There is [extensive documentation](https://ruby.github.io/prism/) on how to use Prism
- * Prism is both a C library that will be used internally by CRuby and a Ruby gem that can be used by any tooling which needs to parse Ruby code
- * Notable methods in the Prism API are:
- * `Prism.parse(source)` which returns the AST as part of a parse result object
- * `Prism.parse_comments(source)` which returns the comments
- * `Prism.parse_success?(source)` which returns true if there are no errors
-* You can make pull requests or issues directly on [the Prism repository](https://github.com/ruby/prism) if you are interested in contributing
-* You can now use `ruby --parser=prism` or `RUBYOPT="--parser=prism"` to experiment with the Prism compiler. Please note that this flag is for debugging only.
+* 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
-* Subprocess creation/forking via the following file open methods is deprecated. [[Feature #19630]]
- * Kernel#open
- * URI.open
- * IO.binread
- * IO.foreach
- * IO.readlines
- * IO.read
- * IO.write
+* `String#to_c` currently treat a sequence of underscores as an end of Complex
+ string. [[Bug #19087]]
-* When given a non-lambda, non-literal block, Kernel#lambda with now raises
- ArgumentError instead of returning it unmodified. These usages have been
- issuing warnings under the `Warning[:deprecated]` category since Ruby 3.0.0.
- [[Feature #19777]]
+* Now `ENV.clone` raises `TypeError` as well as `ENV.dup` [[Bug #17767]]
-* 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]]
+### Removed constants
-* `it` calls without arguments in a block with no ordinary parameters are
- deprecated. `it` will be a reference to the first block parameter in Ruby 3.4.
- [[Feature #18980]]
+The following deprecated constants are removed.
-* Error message for NoMethodError have changed to not use the target object's `#inspect`
- for efficiency, and says "instance of ClassName" instead. [[Feature #18285]]
+* `Fixnum` and `Bignum` [[Feature #12005]]
+* `Random::DEFAULT` [[Feature #17351]]
+* `Struct::Group`
+* `Struct::Passwd`
- ```ruby
- ([1] * 100).nonexisting
- # undefined method `nonexisting' for an instance of Array (NoMethodError)
- ```
+### Removed methods
-* Now anonymous parameters forwarding is disallowed inside a block
- that uses anonymous parameters. [[Feature #19370]]
+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
-* `rb_postponed_job` updates
- * New APIs and deprecated APIs (see comments for details)
- * added: `rb_postponed_job_preregister()`
- * added: `rb_postponed_job_trigger()`
- * deprecated: `rb_postponed_job_register()` (and semantic change. see below)
- * deprecated: `rb_postponed_job_register_one()`
- * The postponed job APIs have been changed to address some rare crashes.
- To solve the issue, we introduced new two APIs and deprecated current APIs.
- The semantics of these functions have also changed slightly; `rb_postponed_job_register`
- now behaves like the `once` variant in that multiple calls with the same
- `func` might be coalesced into a single execution of the `func`
- [[Feature #20057]]
-
-* Some updates for internal thread event hook APIs
- * `rb_internal_thread_event_data_t` with a target Ruby thread (VALUE)
- and callback functions (`rb_internal_thread_event_callback`) receive it.
- https://github.com/ruby/ruby/pull/8885
- * The following functions are introduced to manipulate Ruby thread local data
- from internal thread event hook APIs (they are introduced since Ruby 3.2).
- https://github.com/ruby/ruby/pull/8936
- * `rb_internal_thread_specific_key_create()`
- * `rb_internal_thread_specific_get()`
- * `rb_internal_thread_specific_set()`
-
-* `rb_profile_thread_frames()` is introduced to get a frames from
- a specific thread.
- [[Feature #10602]]
-
-* `rb_data_define()` is introduced to define `Data`. [[Feature #19757]]
-
-* `rb_ext_resolve_symbol()` is introduced to search a function from
- extension libraries. [[Feature #20005]]
-
-* IO related updates:
- * The details of `rb_io_t` will be hidden and deprecated attributes
- are added for each members. [[Feature #19057]]
- * `rb_io_path(VALUE io)` is introduced to get a path of `io`.
- * `rb_io_closed_p(VALUE io)` to get opening or closing of `io`.
- * `rb_io_mode(VALUE io)` to get the mode of `io`.
- * `rb_io_open_descriptor()` is introduced to make an IO object from a file
- descriptor.
+### 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
-### Parser
-
-* Replace Bison with [Lrama LALR parser generator](https://github.com/ruby/lrama).
- No need to install Bison to build Ruby from source code anymore.
- We will no longer suffer bison compatibility issues and we can use new features by just implementing it to Lrama. [[Feature #19637]]
- * See [The future vision of Ruby Parser](https://rubykaigi.org/2023/presentations/spikeolaf.html) for detail.
- * Lrama internal parser is a LR parser generated by Racc for maintainability.
- * Parameterizing Rules `(?, *, +)` are supported, it will be used in Ruby parse.y.
-
-### GC / Memory management
-
-* Major performance improvements over Ruby 3.2
- * Young objects referenced by old objects are no longer immediately
- promoted to the old generation. This significantly reduces the frequency of
- major GC collections. [[Feature #19678]]
- * A new `REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO` tuning variable was
- introduced to control the number of unprotected objects cause a major GC
- collection to trigger. The default is set to `0.01` (1%). This significantly
- reduces the frequency of major GC collection. [[Feature #19571]]
- * Write Barriers were implemented for many core types that were missing them,
- notably `Time`, `Enumerator`, `MatchData`, `Method`, `File::Stat`, `BigDecimal`
- and several others. This significantly reduces minor GC collection time and major
- GC collection frequency.
- * Most core classes are now using Variable Width Allocation, notably `Hash`, `Time`,
- `Thread::Backtrace`, `Thread::Backtrace::Location`, `File::Stat`, `Method`.
- This makes these classes faster to allocate and free, use less memory and reduce
- heap fragmentation.
-* `defined?(@ivar)` is optimized with Object Shapes.
+* 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 Ruby 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.
- * Unsupported call types and megamorphic call sites no longer exit to the interpreter.
- * Basic methods like Rails `#blank?` and
- [specialized `#present?`](https://github.com/rails/rails/pull/49909) are inlined.
- * `Integer#*`, `Integer#!=`, `String#!=`, `String#getbyte`,
- `Kernel#block_given?`, `Kernel#is_a?`, `Kernel#instance_of?`, and `Module#===`
- are specially optimized.
- * Compilation speed is now slightly faster than Ruby 3.2.
- * Now more than 3x faster than the interpreter on Optcarrot!
-* Significantly improved memory usage over Ruby 3.2
- * Metadata for compiled code uses a lot less memory.
- * `--yjit-call-threshold` is automatically raised from 30 to 120
- when the application has more than 40,000 ISEQs.
- * `--yjit-cold-threshold` is added to skip compiling cold ISEQs.
- * More compact code is generated on Arm64.
-* Code GC is now disabled by default
- * `--yjit-exec-mem-size` is treated as a hard limit where compilation of new code stops.
- * No sudden drops in performance due to code GC.
- Better copy-on-write behavior on servers reforking with
- [Pitchfork](https://github.com/shopify/pitchfork).
- * You can still enable code GC if desired with `--yjit-code-gc`
-* Add `RubyVM::YJIT.enable` that can enable YJIT at run-time
- * You can start YJIT without modifying command-line arguments or environment variables.
- Rails 7.2 will [enable YJIT by default](https://github.com/rails/rails/pull/49947)
- using this method.
- * 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.
-* More YJIT stats are available by default
- * `yjit_alloc_size` and several more metadata-related stats are now available by default.
- * `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.
-* Add more profiling capabilities
- * `--yjit-perf` is added to facilitate profiling with Linux perf.
- * `--yjit-trace-exits` now supports sampling with `--yjit-trace-exits-sample-rate=N`
-* More thorough testing and multiple bug fixes
-* `--yjit-stats=quiet` is added to avoid printing stats on exit.
+* 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 Thread 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 goroutine 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.
-
-[Bug #595]: https://bugs.ruby-lang.org/issues/595
-[Feature #10602]: https://bugs.ruby-lang.org/issues/10602
-[Bug #17146]: https://bugs.ruby-lang.org/issues/17146
-[Feature #18183]: https://bugs.ruby-lang.org/issues/18183
-[Feature #18285]: https://bugs.ruby-lang.org/issues/18285
-[Feature #18498]: https://bugs.ruby-lang.org/issues/18498
-[Feature #18515]: https://bugs.ruby-lang.org/issues/18515
-[Feature #18551]: https://bugs.ruby-lang.org/issues/18551
-[Feature #18885]: https://bugs.ruby-lang.org/issues/18885
-[Feature #18949]: https://bugs.ruby-lang.org/issues/18949
-[Feature #18980]: https://bugs.ruby-lang.org/issues/18980
-[Bug #19012]: https://bugs.ruby-lang.org/issues/19012
-[Feature #19057]: https://bugs.ruby-lang.org/issues/19057
-[Bug #19150]: https://bugs.ruby-lang.org/issues/19150
-[Bug #19293]: https://bugs.ruby-lang.org/issues/19293
-[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 #19370]: https://bugs.ruby-lang.org/issues/19370
-[Feature #19521]: https://bugs.ruby-lang.org/issues/19521
-[Feature #19538]: https://bugs.ruby-lang.org/issues/19538
-[Feature #19561]: https://bugs.ruby-lang.org/issues/19561
-[Feature #19571]: https://bugs.ruby-lang.org/issues/19571
-[Feature #19572]: https://bugs.ruby-lang.org/issues/19572
-[Feature #19591]: https://bugs.ruby-lang.org/issues/19591
-[Feature #19630]: https://bugs.ruby-lang.org/issues/19630
-[Feature #19637]: https://bugs.ruby-lang.org/issues/19637
-[Feature #19678]: https://bugs.ruby-lang.org/issues/19678
-[Feature #19714]: https://bugs.ruby-lang.org/issues/19714
-[Feature #19725]: https://bugs.ruby-lang.org/issues/19725
-[Feature #19757]: https://bugs.ruby-lang.org/issues/19757
-[Feature #19776]: https://bugs.ruby-lang.org/issues/19776
-[Feature #19777]: https://bugs.ruby-lang.org/issues/19777
-[Feature #19785]: https://bugs.ruby-lang.org/issues/19785
-[Feature #19790]: https://bugs.ruby-lang.org/issues/19790
-[Feature #19839]: https://bugs.ruby-lang.org/issues/19839
-[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
-[Feature #20005]: https://bugs.ruby-lang.org/issues/20005
-[Feature #20057]: https://bugs.ruby-lang.org/issues/20057
+* 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..bb69c09055 100644
--- a/README.ja.md
+++ b/README.ja.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)
@@ -26,7 +26,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 +50,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 +71,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 +163,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..35ef2d9e89 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
[![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)
# What is Ruby?
@@ -24,20 +25,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 +48,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 +64,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..f7d5b0239b 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,19 @@ 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)
-{
- if (size == 4) {
- set_uint_value(v, read_uint32(&reader->p));
- } else if (size == 8) {
- set_uint_value(v, read_uint64(&reader->p));
- } else {
- return false;
- }
- 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);
+ if (reader->address_size == 4) {
+ set_uint_value(v, read_uint32(&reader->p));
+ } else if (reader->address_size == 8) {
+ set_uint_value(v, read_uint64(&reader->p));
+ } else {
+ fprintf(stderr,"unknown address_size:%d", reader->address_size);
+ abort();
+ }
break;
case DW_FORM_block2:
v->size = read_uint16(&reader->p);
@@ -1246,12 +1208,13 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
set_uint_value(v, read_uleb128(reader));
break;
case DW_FORM_ref_addr:
- 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);
+ 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 {
- debug_info_reader_read_addr_value(reader, v, format);
+ fprintf(stderr,"unknown format:%d", reader->format);
+ abort();
}
break;
case DW_FORM_ref1:
@@ -1352,28 +1315,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 +1341,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 +1353,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 +1406,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 +1418,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 +1449,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 +1469,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 +1489,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 +1507,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 +1552,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 +1620,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 +1636,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 +1657,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 +1719,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 +1743,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 +1772,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 +1809,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 +1828,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 +1880,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 +1908,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 +1926,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 +1936,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 +1991,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 +2151,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 +2193,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 +2208,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 +2220,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 +2299,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 +2421,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 +2442,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 +2450,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 +2464,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 +2478,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 +2490,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 +2531,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 +2552,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 +2596,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 +2605,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 +2639,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 e1b8553568..654c79a44d 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,18 +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 {
- const VALUE *ptr = RARRAY_CONST_PTR(ary);
+#if 1
+ 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 */
@@ -257,7 +287,16 @@ ary_verify_(VALUE ary, const char *file, int line)
v = ptr[i]; /* access check */
}
v = v;
+#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;
}
@@ -277,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
@@ -299,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);
});
}
@@ -315,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);
});
@@ -328,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]);
}
@@ -349,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));
+ }
}
}
@@ -403,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);
@@ -507,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
@@ -543,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);
@@ -587,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);
@@ -665,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);
@@ -678,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;
}
@@ -694,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)");
@@ -713,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);
}
@@ -751,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;
@@ -776,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);
@@ -789,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)");
@@ -817,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);
}
@@ -842,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;
}
@@ -864,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);
@@ -893,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)) {
@@ -903,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);
@@ -917,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);
@@ -949,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;
}
@@ -977,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);
@@ -1052,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+:
*
@@ -1192,22 +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);
- /* The ary_make_shared call may allocate, which can trigger a GC
- * compaction. This can cause the array to be embedded because it has
- * a length of 0. */
- FL_UNSET_EMBED(result);
+ 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);
@@ -1215,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
@@ -1229,13 +1381,12 @@ 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_TRANSIENT(ary);
const long orig_len = len;
if (step > 0 && step >= len) {
VALUE result = ary_new(klass, 1);
VALUE *ptr = (VALUE *)ARY_EMBED_PTR(result);
- const VALUE *values = RARRAY_CONST_PTR(ary);
-
RB_OBJ_WRITE(result, ptr, values[offset]);
ARY_SET_EMBED_LEN(result, 1);
return result;
@@ -1253,8 +1404,6 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step)
VALUE result = ary_new(klass, len);
if (ARY_EMBED_P(result)) {
VALUE *ptr = (VALUE *)ARY_EMBED_PTR(result);
- const VALUE *values = RARRAY_CONST_PTR(ary);
-
for (i = 0; i < len; ++i) {
RB_OBJ_WRITE(result, ptr+i, values[j]);
j += step;
@@ -1262,9 +1411,7 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step)
ARY_SET_EMBED_LEN(result, len);
}
else {
- const VALUE *values = RARRAY_CONST_PTR(ary);
-
- 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;
@@ -1289,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;
}
@@ -1306,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
@@ -1339,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);
@@ -1374,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.
*/
@@ -1418,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]
@@ -1482,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]
@@ -1518,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) {
@@ -1529,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);
@@ -1590,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);
});
@@ -1627,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);
@@ -1645,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);
@@ -1668,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 */
@@ -1732,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
@@ -1747,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]
@@ -1767,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:
*
@@ -1821,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
@@ -1844,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;
@@ -1870,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
@@ -1883,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)
{
@@ -1895,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);
@@ -1929,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]
@@ -2019,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.
*/
@@ -2073,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
@@ -2145,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;
}
@@ -2158,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);
@@ -2176,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));
}
}
@@ -2239,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 */
@@ -2270,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;
}
@@ -2283,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+:
*
@@ -2303,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+:
*
@@ -2338,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+:
*
@@ -2418,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+
@@ -2512,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
@@ -2569,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
@@ -2626,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
@@ -2693,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);
@@ -2846,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>.
@@ -2906,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
@@ -2964,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']]
@@ -3039,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 */
@@ -3083,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));
@@ -3126,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;
}
}
@@ -3145,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]
@@ -3202,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]
@@ -3221,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]
@@ -3248,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);
@@ -3387,9 +3590,6 @@ rb_ary_sort_bang(VALUE ary)
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
}
- if (ARY_EMBED_LEN(tmp) > ARY_CAPA(ary)) {
- ary_resize_capa(ary, ARY_EMBED_LEN(tmp));
- }
ary_memcpy(ary, 0, ARY_EMBED_LEN(tmp), ARY_EMBED_PTR(tmp));
ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
}
@@ -3536,8 +3736,8 @@ rb_ary_bsearch_index(VALUE ary)
const VALUE zero = INT2FIX(0);
switch (rb_cmpint(rb_funcallv(v, id_cmp, 1, &zero), v, zero)) {
case 0: return INT2FIX(mid);
- case 1: smaller = 0; break;
- case -1: smaller = 1;
+ case 1: smaller = 1; break;
+ case -1: smaller = 0;
}
}
else {
@@ -3582,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!>
@@ -3614,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
@@ -3647,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
@@ -3704,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) {
@@ -3727,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+:
*
@@ -3791,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
@@ -3850,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);
});
}
@@ -3874,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
@@ -3905,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>
@@ -4037,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);
@@ -4049,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+:
*
@@ -4098,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;
}
@@ -4112,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]
@@ -4147,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]
@@ -4263,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!>
@@ -4290,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>
@@ -4319,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)
@@ -4539,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);
@@ -4555,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 {
@@ -4621,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>),
@@ -4649,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+:
@@ -4675,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>),
@@ -4887,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;
}
@@ -4898,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;
@@ -4946,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}"
@@ -4987,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:
@@ -5055,7 +5261,7 @@ rb_ary_rassoc(VALUE ary, VALUE value)
VALUE v;
for (i = 0; i < RARRAY_LEN(ary); ++i) {
- v = rb_check_array_type(RARRAY_AREF(ary, i));
+ v = RARRAY_AREF(ary, i);
if (RB_TYPE_P(v, T_ARRAY) &&
RARRAY_LEN(v) > 1 &&
rb_equal(RARRAY_AREF(v, 1), value))
@@ -5127,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);
}
@@ -5167,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
@@ -5204,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);
}
/*
@@ -5364,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
@@ -5405,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;
}
@@ -5468,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]
@@ -5512,6 +5722,7 @@ rb_ary_and(VALUE ary1, VALUE ary2)
rb_ary_push(ary3, v);
}
}
+ ary_recycle_hash(hash);
return ary3;
}
@@ -5522,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]
@@ -5599,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;
@@ -5612,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;
}
/*
@@ -5636,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++) {
@@ -5645,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]);
@@ -5656,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;
}
/*
@@ -5672,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
@@ -5712,6 +5924,7 @@ rb_ary_intersect_p(VALUE ary1, VALUE ary2)
break;
}
}
+ ary_recycle_hash(hash);
return result;
}
@@ -5818,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:
@@ -5986,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]
@@ -6061,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:
@@ -6146,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;
}
@@ -6190,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;
}
@@ -6210,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;
}
@@ -6305,8 +6522,9 @@ static VALUE
flatten(VALUE ary, int level)
{
long i;
- VALUE stack, result, tmp = 0, elt;
- VALUE memo = Qfalse;
+ VALUE stack, result, tmp = 0, elt, vmemo;
+ st_table *memo = 0;
+ st_data_t id;
for (i = 0; i < RARRAY_LEN(ary); i++) {
elt = RARRAY_AREF(ary, i);
@@ -6320,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);
@@ -6328,9 +6546,12 @@ flatten(VALUE ary, int level)
rb_ary_push(stack, LONG2NUM(i + 1));
if (level < 0) {
- memo = rb_obj_hide(rb_ident_hash_new());
- rb_hash_aset(memo, ary, Qtrue);
- rb_hash_aset(memo, tmp, Qtrue);
+ vmemo = rb_hash_new();
+ RBASIC_CLEAR_CLASS(vmemo);
+ memo = st_init_numtable();
+ 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);
}
ary = tmp;
@@ -6345,8 +6566,9 @@ flatten(VALUE ary, int level)
}
tmp = rb_check_array_type(elt);
if (RBASIC(result)->klass) {
- if (RTEST(memo)) {
- rb_hash_clear(memo);
+ if (memo) {
+ RB_GC_GUARD(vmemo);
+ st_clear(memo);
}
rb_raise(rb_eRuntimeError, "flatten reentered");
}
@@ -6355,11 +6577,12 @@ flatten(VALUE ary, int level)
}
else {
if (memo) {
- if (rb_hash_aref(memo, tmp) == Qtrue) {
- rb_hash_clear(memo);
+ id = (st_data_t)tmp;
+ if (st_is_member(memo, id)) {
+ st_clear(memo);
rb_raise(rb_eArgError, "tried to flatten recursive array");
}
- rb_hash_aset(memo, tmp, Qtrue);
+ st_insert(memo, id, (st_data_t)Qtrue);
}
rb_ary_push(stack, ary);
rb_ary_push(stack, LONG2NUM(i));
@@ -6371,7 +6594,8 @@ flatten(VALUE ary, int level)
break;
}
if (memo) {
- rb_hash_delete(memo, ary);
+ id = (st_data_t)ary;
+ st_delete(memo, &id, 0);
}
tmp = rb_ary_pop(stack);
i = NUM2LONG(tmp);
@@ -6379,7 +6603,7 @@ flatten(VALUE ary, int level)
}
if (memo) {
- rb_hash_clear(memo);
+ st_clear(memo);
}
RBASIC_SET_CLASS(result, rb_cArray);
@@ -6394,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]
@@ -6448,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]
@@ -6504,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];
@@ -6596,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]);
}
@@ -6619,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;
@@ -6682,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+:
*
@@ -6701,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>
@@ -6858,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:
@@ -6920,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>
@@ -7004,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:
@@ -7043,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)>
@@ -7141,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>.
*
@@ -7178,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)>
@@ -7273,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>.
*
@@ -7307,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)>
@@ -7515,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:
@@ -7555,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>
*
@@ -7578,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:
@@ -7619,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>
*
@@ -7645,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:
*
@@ -7709,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:
*
@@ -7997,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)
@@ -8087,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)
@@ -8098,7 +8309,6 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
return v;
}
-/* :nodoc: */
static VALUE
rb_ary_deconstruct(VALUE ary)
{
@@ -8626,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_dup.yml b/benchmark/string_dup.yml
deleted file mode 100644
index 90793f9f2a..0000000000
--- a/benchmark/string_dup.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-prelude: |
- # frozen_string_literal: true
-benchmark:
- uplus: |
- +"A"
- dup: |
- "A".dup
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/struct_accessor.yml b/benchmark/struct_accessor.yml
deleted file mode 100644
index 61176cfdd4..0000000000
--- a/benchmark/struct_accessor.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-prelude: |
- C = Struct.new(:x) do
- class_eval <<-END
- def r
- #{'x;'*256}
- end
- def w
- #{'self.x = nil;'*256}
- end
- def rm
- m = method(:x)
- #{'m.call;'*256}
- end
- def wm
- m = method(:x=)
- #{'m.call(nil);'*256}
- end
- END
- end
- obj = C.new(nil)
-benchmark:
- member_reader: "obj.r"
- member_writer: "obj.w"
- member_reader_method: "obj.rm"
- member_writer_method: "obj.wm"
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_method_splat_calls.yml b/benchmark/vm_method_splat_calls.yml
deleted file mode 100644
index f2f366e99c..0000000000
--- a/benchmark/vm_method_splat_calls.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-prelude: |
- def f(x=0, y: 0) end
- a = [1]
- ea = []
- kw = {y: 1}
- b = lambda{}
-benchmark:
- arg_splat: "f(1, *ea)"
- arg_splat_block: "f(1, *ea, &b)"
- splat_kw_splat: "f(*a, **kw)"
- splat_kw_splat_block: "f(*a, **kw, &b)"
- splat_kw: "f(*a, y: 1)"
- splat_kw_block: "f(*a, y: 1, &b)"
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..8ef19e9751 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;
@@ -4591,14 +4586,11 @@ big_shift3(VALUE x, int lshift_p, size_t shift_numdigits, int shift_numbits)
if (lshift_p) {
if (LONG_MAX < shift_numdigits) {
- too_big:
- rb_raise(rb_eRangeError, "shift width too big");
+ rb_raise(rb_eArgError, "too big number");
}
s1 = shift_numdigits;
s2 = shift_numbits;
- if ((size_t)s1 != shift_numdigits) goto too_big;
xn = BIGNUM_LEN(x);
- if (LONG_MAX/SIZEOF_BDIGIT <= xn+s1) goto too_big;
z = bignew(xn+s1+1, BIGNUM_SIGN(x));
zds = BDIGITS(z);
BDIGITS_ZERO(zds, s1);
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 a34527d2fa..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
@@ -552,13 +552,8 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
filename = "bootstraptest.#{self.path}_#{self.lineno}_#{self.id}.rb"
File.open(filename, 'w') {|f|
f.puts "#frozen_string_literal:true" if frozen_string_literal
- if $stress
- f.puts "GC.stress = true" if $stress
- else
- f.puts ""
- end
- f.puts "class BT_Skip < Exception; end; def skip(msg) = raise(BT_Skip, msg.to_s)"
- f.puts "print(begin; #{self.src}; rescue BT_Skip; $!.message; end)"
+ f.puts "GC.stress = true" if $stress
+ f.puts "print(begin; #{self.src}; end)"
}
filename
end
@@ -674,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
@@ -789,9 +784,4 @@ def check_coredump
end
end
-def rjit_enabled?
- # Don't check `RubyVM::RJIT.enabled?`. On btest-bruby, target Ruby != runner Ruby.
- ENV.fetch('RUN_OPTS', '').include?('rjit')
-end
-
exit main
diff --git a/bootstraptest/test_eval.rb b/bootstraptest/test_eval.rb
index 47e2924846..a9f389c673 100644
--- a/bootstraptest/test_eval.rb
+++ b/bootstraptest/test_eval.rb
@@ -227,16 +227,6 @@ assert_equal %q{[10, main]}, %q{
}, '[ruby-dev:31372]'
end
-assert_normal_exit %{
- $stderr = STDOUT
- 5000.times do
- begin
- eval "0 rescue break"
- rescue SyntaxError
- end
- end
-}
-
assert_normal_exit %q{
$stderr = STDOUT
class Foo
diff --git a/bootstraptest/test_fork.rb b/bootstraptest/test_fork.rb
index 0cdfb5ab24..83923dad97 100644
--- a/bootstraptest/test_fork.rb
+++ b/bootstraptest/test_fork.rb
@@ -75,29 +75,3 @@ assert_equal '[1, 2]', %q{
end
}, '[ruby-dev:44005] [Ruby 1.9 - Bug #4950]'
-assert_equal 'ok', %q{
- # This test is very unstable. It fails a Ractor assertion:
- # Assertion Failed: ../src/thread_pthread.c:451:ractor_sched_set_locked:vm->ractor.sched.lock_owner == NULL
- skip :ok # too unstable
-
- def now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- Thread.new do
- loop { sleep 0.0001 }
- end
-
- 10.times do
- pid = fork{ exit!(0) }
- deadline = now + 1
- until Process.waitpid(pid, Process::WNOHANG)
- if now > deadline
- Process.kill(:KILL, pid)
- raise "failed"
- end
- sleep 0.001
- end
- rescue NotImplementedError
- end
- :ok
-}, '[Bug #20670]'
-
diff --git a/bootstraptest/test_gc.rb b/bootstraptest/test_gc.rb
index 17bc497822..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 rjit_enabled? # 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_method.rb b/bootstraptest/test_method.rb
index 964bf39d98..04c9eb2d11 100644
--- a/bootstraptest/test_method.rb
+++ b/bootstraptest/test_method.rb
@@ -1190,12 +1190,3 @@ assert_equal 'DC', %q{
test2 o1, [], block
$result.join
}
-
-assert_equal 'ok', %q{
- def foo
- binding
- ["ok"].first
- end
- foo
- foo
-}, '[Bug #20178]'
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index ea7c2c197d..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
@@ -1401,7 +1397,7 @@ assert_equal '[false, false, true, true]', %q{
}
# TracePoint with normal Proc should be Ractor local
-assert_equal '[6, 10]', %q{
+assert_equal '[4, 8]', %q{
rs = []
TracePoint.new(:line){|tp| rs << tp.lineno if tp.path == __FILE__}.enable do
Ractor.new{ # line 4
@@ -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/ || ENV.key?('CI') # 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,166 +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)
}
-# check moved object
-assert_equal 'ok', %q{
- r = Ractor.new do
- Ractor.receive
- GC.start
- :ok
- end
-
- obj = begin
- raise
- rescue => e
- e = Marshal.load(Marshal.dump(e))
- end
-
- r.send obj, move: true
- r.take
-}
-
-## Ractor::Selector
-
-# Selector#empty? returns true
-assert_equal 'true', %q{
- skip true unless defined? Ractor::Selector
-
- s = Ractor::Selector.new
- s.empty?
-}
-
-# Selector#empty? returns false if there is target ractors
-assert_equal 'false', %q{
- skip false unless defined? Ractor::Selector
-
- s = Ractor::Selector.new
- s.add Ractor.new{}
- s.empty?
-}
-
-# Selector#clear removes all ractors from the waiting list
-assert_equal 'true', %q{
- skip true unless defined? Ractor::Selector
-
- 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{
- skip [10, 20, true] unless defined? Ractor::Selector
-
- 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?]
-} if defined? Ractor::Selector
-
-# Selector#wait can wait multiple ractors with receiving.
-assert_equal '30', %q{
- skip 30 unless defined? Ractor::Selector
-
- 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
-} if defined? Ractor::Selector
-
-# 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{
- skip 600 unless defined? Ractor::Selector
-
- 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{
- skip :ok unless defined? Ractor::Selector
-
- 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 e123f35160..0000000000
--- a/bootstraptest/test_rjit.rb
+++ /dev/null
@@ -1,58 +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
-}
-
-# Updating local type in Context
-assert_normal_exit %q{
- def foo(flag, object)
- klass = if flag
- object
- end
- klass ||= object
- return klass.new
- end
-
- foo(false, Object)
- foo(true, Object)
-}
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 a4d46e2f10..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
@@ -303,7 +289,7 @@ assert_normal_exit %q{
}.each {|t|
t.join
}
-} unless rjit_enabled? # flaky
+}
assert_equal 'ok', %q{
def m
@@ -497,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 31b9aabf11..9d9143d265 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1,297 +1,3 @@
-# regression test for popping before side exit
-assert_equal "ok", %q{
- def foo(a, *) = a
-
- def call(args, &)
- foo(1) # spill at where the block arg will be
- foo(*args, &)
- end
-
- call([1, 2])
-
- begin
- call([])
- rescue ArgumentError
- :ok
- end
-}
-
-# regression test for send processing before side exit
-assert_equal "ok", %q{
- def foo(a, *) = :foo
-
- def call(args)
- send(:foo, *args)
- end
-
- call([1, 2])
-
- begin
- call([])
- rescue ArgumentError
- :ok
- end
-}
-
-# test discarding extra yield arguments
-assert_equal "2210150001501015", %q{
- def splat_kw(ary) = yield *ary, a: 1
-
- def splat(ary) = yield *ary
-
- def kw = yield 1, 2, a: 0
-
- def simple = yield 0, 1
-
- def calls
- [
- splat([1, 1, 2]) { |x, y| x + y },
- splat([1, 1, 2]) { |y, opt = raise| opt + y},
- splat_kw([0, 1]) { |a:| a },
- kw { |a:| a },
- kw { |a| a },
- simple { 5.itself },
- simple { |a| a },
- simple { |opt = raise| opt },
- simple { |*rest| rest },
- simple { |opt_kw: 5| opt_kw },
- # autosplat ineractions
- [0, 1, 2].yield_self { |a, b| [a, b] },
- [0, 1, 2].yield_self { |a, opt = raise| [a, opt] },
- [1].yield_self { |a, opt = 4| a + opt },
- ]
- end
-
- calls.join
-}
-
-# test autosplat with empty splat
-assert_equal "ok", %q{
- def m(pos, splat) = yield pos, *splat
-
- m([:ok], []) {|v0,| v0 }
-}
-
-# regression test for send stack shifting
-assert_normal_exit %q{
- def foo(a, b)
- a.singleton_methods(b)
- end
-
- def call_foo
- [1, 1, 1, 1, 1, 1, send(:foo, 1, 1)]
- end
-
- call_foo
-}
-
-# regression test for keyword splat with yield
-assert_equal 'nil', %q{
- def splat_kw(kwargs) = yield(**kwargs)
-
- splat_kw({}) { _1 }.inspect
-} unless rjit_enabled? # Not yet working on RJIT
-
-# regression test for arity check with splat
-assert_equal '[:ae, :ae]', %q{
- def req_one(a_, b_ = 1) = raise
-
- def test(args)
- req_one *args
- rescue ArgumentError
- :ae
- end
-
- [test(Array.new 5), test([])]
-} unless rjit_enabled? # Not yet working on RJIT
-
-# regression test for arity check with splat and send
-assert_equal '[:ae, :ae]', %q{
- def two_reqs(a, b_, _ = 1) = a.gsub(a, a)
-
- def test(name, args)
- send(name, *args)
- rescue ArgumentError
- :ae
- end
-
- [test(:two_reqs, ["g", nil, nil, nil]), test(:two_reqs, ["g"])]
-}
-
-# regression test for GC marking stubs in invalidated code
-assert_normal_exit %q{
- garbage = Array.new(10_000) { [] } # create garbage to cause iseq movement
- eval(<<~RUBY)
- def foo(n, garbage)
- if n == 2
- # 1.times.each to create a cfunc frame to preserve the JIT frame
- # which will return to a stub housed in an invalidated block
- return 1.times.each do
- Object.define_method(:foo) {}
- garbage.clear
- GC.verify_compaction_references(toward: :empty, expand_heap: true)
- end
- end
-
- foo(n + 1, garbage)
- end
- RUBY
-
- foo(1, garbage)
-}
-
-# 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 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{
- def yielder(arg) = yield(arg) + yield(arg)
-
- yielder([:a, :b]) do |c = :c, d = :d|
- [c, d]
- end
-}
-
-# Regression test for GC mishap while doing shape transition
-assert_equal '[:ok]', %q{
- # [Bug #19601]
- class RegressionTest
- def initialize
- @a = @b = @fourth_ivar_does_shape_transition = nil
- end
-
- def extender
- @first_extended_ivar = [:ok]
- end
- end
-
- GC.stress = true
-
- # Used to crash due to GC run in rb_ensure_iv_list_size()
- # not marking the newly allocated [:ok].
- RegressionTest.new.extender.itself
-} unless rjit_enabled? # Skip on RJIT since this uncovers a crash
-
assert_equal 'true', %q{
# regression test for tracking type of locals for too long
def local_setting_cmp(five)
@@ -340,7 +46,7 @@ assert_normal_exit %q{
}
assert_normal_exit %q{
- # Test to ensure send on overridden c functions
+ # Test to ensure send on overriden c functions
# doesn't corrupt the stack
class Bar
def bar(x)
@@ -373,80 +79,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
-}
-
-# getinstancevariable with shape too complex
-assert_normal_exit %q{
- class Foo
- def initialize
- @a = 1
- end
-
- def getter
- @foobar
- end
- end
-
- # Initialize ivars in changing order, making the Foo
- # class have shape too complex
- 100.times do |x|
- foo = Foo.new
- foo.instance_variable_set(:"@a#{x}", 1)
- foo.instance_variable_set(:"@foobar", 777)
-
- # The getter method eventually sees shape too complex
- r = foo.getter
- if r != 777
- raise "error"
- end
- end
-}
-
assert_equal '0', %q{
# This is a regression test for incomplete invalidation from
# opt_setinlinecache. This test might be brittle, so
@@ -589,8 +221,6 @@ 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
@@ -744,45 +374,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)
@@ -1393,18 +984,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{
@@ -1562,38 +1141,6 @@ assert_equal '42', %q{
run
}
-# splatting an empty array on a specialized method
-assert_equal 'ok', %q{
- def run
- "ok".to_s(*[])
- end
-
- run
- run
-}
-
-# splatting an single element array on a specialized method
-assert_equal '[1]', %q{
- def run
- [].<<(*[1])
- end
-
- run
- run
-}
-
-# specialized method with wrong args
-assert_equal 'ok', %q{
- def run(x)
- "bad".to_s(123) if x
- rescue
- :ok
- end
-
- run(false)
- run(true)
-}
-
# getinstancevariable on Symbol
assert_equal '[nil, nil]', %q{
# @foo to exercise the getinstancevariable instruction
@@ -2027,24 +1574,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 rjit_enabled? # Not yet working on RJIT
-
# Test << operator on string subclass
assert_equal 'abab', %q{
class MyString < String; end
@@ -2411,38 +1940,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)
@@ -2523,18 +2020,6 @@ assert_equal '[1, 2, 3, 4, 5]', %q{
splatarray
}
-# splatkw
-assert_equal '[1, 2]', %q{
- def foo(a:) = [a, yield]
-
- def entry(&block)
- a = { a: 1 }
- foo(**a, &block)
- end
-
- entry { 2 }
-}
-
assert_equal '[1, 1, 2, 1, 2, 3]', %q{
def expandarray
arr = [1, 2, 3]
@@ -2599,17 +2084,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]
@@ -2699,7 +2173,7 @@ assert_equal '[[:c_return, :String, :string_alias, "events_to_str"]]', %q{
events.compiled(events)
events
-} unless 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{
@@ -2781,7 +2255,7 @@ assert_equal '[[:c_call, :itself]]', %q{
tp.enable { shouldnt_compile }
events
-} unless 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{
@@ -2796,7 +2270,7 @@ assert_equal '[[:c_return, :itself, main]]', %q{
tp.enable { shouldnt_compile }
events
-} unless 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{
@@ -3982,538 +3456,3 @@ 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
-
- 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
-}
-
-# Regression 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 rjit_enabled? # Not yet working on RJIT
-
-# Regression 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
- 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 }
-}
-
-assert_normal_exit %q{
- ivars = 1024.times.map { |i| "@iv_#{i} = #{i}\n" }.join
- Foo = Class.new
- Foo.class_eval "def initialize() #{ivars} end"
- Foo.new
-}
-
-assert_equal '0', %q{
- def spill
- 1.to_i # not inlined
- end
-
- def inline(_stack1, _stack2, _stack3, _stack4, _stack5)
- 0 # inlined
- end
-
- def entry
- # RegTemps is 00111110 prior to the #inline call.
- # Its return value goes to stack_idx=0, which conflicts with stack_idx=5.
- inline(spill, 2, 3, 4, 5)
- end
-
- entry
-}
-
-# Integer succ and overflow
-assert_equal '[2, 4611686018427387904]', %q{
- [1.succ, 4611686018427387903.succ]
-}
-
-# Integer right shift
-assert_equal '[0, 1, -4]', %q{
- [0 >> 1, 2 >> 1, -7 >> 1]
-}
-
-assert_equal '[nil, "yield"]', %q{
- def defined_yield = defined?(yield)
- [defined_yield, defined_yield {}]
-}
-
-# splat with ruby2_keywords into rest parameter
-assert_equal '[[{:a=>1}], {}]', %q{
- ruby2_keywords def foo(*args) = args
-
- def bar(*args, **kw) = [args, kw]
-
- def pass_bar(*args) = bar(*args)
-
- def body
- args = foo(a: 1)
- pass_bar(*args)
- end
-
- body
-}
-
-# regression test for splatting empty array to cfunc
-assert_normal_exit %q{
- def test_body(args) = Array(1, *args)
- test_body([])
- 0x100.times do
- array = Array.new(100)
- array.clear
- test_body(array)
- end
-}
-
-# compiling code shouldn't emit warnings as it may call into more Ruby code
-assert_equal 'ok', <<~'RUBY'
- # [Bug #20522]
- $VERBOSE = true
- Warning[:performance] = true
-
- module StrictWarnings
- def warn(msg, **)
- raise msg
- end
- end
- Warning.singleton_class.prepend(StrictWarnings)
-
- class A
- def compiled_method(is_private)
- @some_ivar = is_private
- end
- end
-
- shape_max_variations = 8
- if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS) && RubyVM::Shape::SHAPE_MAX_VARIATIONS != shape_max_variations
- raise "Expected SHAPE_MAX_VARIATIONS to be #{shape_max_variations}, got: #{RubyVM::Shape::SHAPE_MAX_VARIATIONS}"
- end
-
- 100.times do |i|
- klass = Class.new(A)
- (shape_max_variations - 1).times do |j|
- obj = klass.new
- obj.instance_variable_set("@base_#{i}", 42)
- obj.instance_variable_set("@ivar_#{j}", 42)
- end
- obj = klass.new
- obj.instance_variable_set("@base_#{i}", 42)
- begin
- obj.compiled_method(true)
- rescue
- # expected
- end
- end
-
- :ok
-RUBY
-
-assert_normal_exit %{
- class Bug20997
- def foo(&) = self.class.name(&)
- new.foo
- end
-}
diff --git a/builtin.c b/builtin.c
index 4fc2ab43d1..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
@@ -58,12 +57,6 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
#endif
void
-rb_free_loaded_builtin_table(void)
-{
- // do nothing
-}
-
-void
Init_builtin(void)
{
// nothing
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/ccan/list/list.h b/ccan/list/list.h
index bf692a6937..30b2af04e9 100644
--- a/ccan/list/list.h
+++ b/ccan/list/list.h
@@ -635,16 +635,14 @@ static inline void ccan_list_prepend_list_(struct ccan_list_head *to,
/* internal macros, do not use directly */
#define ccan_list_for_each_off_dir_(h, i, off, dir) \
- for (i = 0, \
- i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \
+ for (i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \
(off)); \
ccan_list_node_from_off_((void *)i, (off)) != &(h)->n; \
i = ccan_list_node_to_off_(ccan_list_node_from_off_((void *)i, (off))->dir, \
(off)))
#define ccan_list_for_each_safe_off_dir_(h, i, nxt, off, dir) \
- for (i = 0, \
- i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \
+ for (i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \
(off)), \
nxt = ccan_list_node_to_off_(ccan_list_node_from_off_(i, (off))->dir, \
(off)); \
diff --git a/class.c b/class.c
index b2a219100c..847c4d0a57 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;
}
@@ -429,31 +404,6 @@ class_init_copy_check(VALUE clone, VALUE orig)
}
}
-struct cvc_table_copy_ctx {
- VALUE clone;
- struct rb_id_table * new_table;
-};
-
-static enum rb_id_table_iterator_result
-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;
-
- struct rb_cvar_class_tbl_entry *ent;
-
- ent = ALLOC(struct rb_cvar_class_tbl_entry);
- ent->class_value = ctx->clone;
- ent->cref = orig_entry->cref;
- ent->global_cvar_state = orig_entry->global_cvar_state;
- rb_id_table_insert(ctx->new_table, id, (VALUE)ent);
-
- RB_OBJ_WRITTEN(ctx->clone, Qundef, ent->cref);
-
- return ID_TABLE_CONTINUE;
-}
-
static void
copy_tables(VALUE clone, VALUE orig)
{
@@ -461,17 +411,6 @@ copy_tables(VALUE clone, VALUE orig)
rb_free_const_table(RCLASS_CONST_TBL(clone));
RCLASS_CONST_TBL(clone) = 0;
}
- if (RCLASS_CVC_TBL(orig)) {
- struct rb_id_table *rb_cvc_tbl = RCLASS_CVC_TBL(orig);
- struct rb_id_table *rb_cvc_tbl_dup = rb_id_table_create(rb_id_table_size(rb_cvc_tbl));
-
- struct cvc_table_copy_ctx ctx;
- ctx.clone = clone;
- ctx.new_table = rb_cvc_tbl_dup;
- rb_id_table_foreach(rb_cvc_tbl, cvc_table_copy, &ctx);
- RCLASS_CVC_TBL(clone) = rb_cvc_tbl_dup;
- }
- rb_id_table_free(RCLASS_M_TBL(clone));
RCLASS_M_TBL(clone) = 0;
if (!RB_TYPE_P(clone, T_ICLASS)) {
st_data_t id;
@@ -496,7 +435,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 +478,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;
@@ -578,14 +517,11 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
rb_bug("non iclass between module/class and origin");
}
clone_p = class_alloc(RBASIC(p)->flags, METACLASS_OF(p));
- /* We should set the m_tbl right after allocation before anything
- * that can trigger GC to avoid clone_p from becoming old and
- * needing to fire write barriers. */
- RCLASS_SET_M_TBL(clone_p, RCLASS_M_TBL(p));
RCLASS_SET_SUPER(prev_clone_p, clone_p);
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);
}
@@ -648,7 +584,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;
}
@@ -670,6 +606,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;
@@ -700,7 +637,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);
}
}
@@ -714,13 +651,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));
}
@@ -866,27 +803,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)
{
@@ -959,7 +875,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;
@@ -1007,7 +923,7 @@ rb_define_class_under(VALUE outer, const char *name, VALUE super)
}
VALUE
-rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super)
+rb_define_class_id_under(VALUE outer, ID id, VALUE super)
{
VALUE klass;
@@ -1024,6 +940,8 @@ rb_define_class_id_under_no_pin(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;
}
@@ -1035,15 +953,8 @@ rb_define_class_id_under_no_pin(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);
-
- 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;
}
@@ -1142,7 +1053,7 @@ rb_include_class_new(VALUE module, VALUE super)
{
VALUE klass = class_alloc(T_ICLASS, rb_cClass);
- RCLASS_SET_M_TBL(klass, RCLASS_M_TBL(module));
+ RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
RCLASS_SET_ORIGIN(klass, klass);
if (BUILTIN_TYPE(module) == T_ICLASS) {
@@ -1194,8 +1105,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. */
@@ -1326,6 +1237,7 @@ 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)};
@@ -1336,11 +1248,14 @@ 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;
}
- VALUE m = module;
- if (BUILTIN_TYPE(m) == T_ICLASS) m = METACLASS_OF(m);
- rb_module_add_to_subclasses_list(m, iclass);
+ if (add_subclass) {
+ 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 =
@@ -1414,10 +1329,10 @@ ensure_origin(VALUE klass)
VALUE origin = RCLASS_ORIGIN(klass);
if (origin == klass) {
origin = class_alloc(T_ICLASS, klass);
- RCLASS_SET_M_TBL(origin, RCLASS_M_TBL(klass));
RCLASS_SET_SUPER(origin, RCLASS_SUPER(klass));
RCLASS_SET_SUPER(klass, origin);
RCLASS_SET_ORIGIN(klass, origin);
+ RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
RCLASS_M_TBL_INIT(klass);
rb_id_table_foreach(RCLASS_M_TBL(origin), cache_clear_refined_method, (void *)klass);
rb_id_table_foreach(RCLASS_M_TBL(origin), move_refined_method, (void *)klass);
@@ -1710,7 +1625,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
@@ -2239,7 +2154,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);
}
@@ -2278,7 +2193,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;
}
@@ -2342,7 +2257,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 fe8c5ed743..3798f82bc6 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)
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,34 +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/encoding.$(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) \
@@ -139,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) \
@@ -162,7 +135,6 @@ COMMONOBJS = array.$(OBJEXT) \
regparse.$(OBJEXT) \
regsyntax.$(OBJEXT) \
ruby.$(OBJEXT) \
- ruby_parser.$(OBJEXT) \
scheduler.$(OBJEXT) \
shape.$(OBJEXT) \
signal.$(OBJEXT) \
@@ -175,6 +147,7 @@ COMMONOBJS = array.$(OBJEXT) \
thread.$(OBJEXT) \
time.$(OBJEXT) \
transcode.$(OBJEXT) \
+ transient_heap.$(OBJEXT) \
util.$(OBJEXT) \
variable.$(OBJEXT) \
version.$(OBJEXT) \
@@ -183,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)/util/.time
-
-$(PRISM_BUILD_DIR)/.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) \
@@ -296,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)
@@ -320,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/' \
@@ -331,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)
@@ -395,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)
@@ -439,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)
@@ -461,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
@@ -660,24 +593,18 @@ 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)"
-undocumented: PHONY main srcs-doc
- $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) "$(srcdir)" | \
- sed -n \
- -e '/^ *# in file /{' -e 's///;N;s/\n/: /p' -e '}' \
- -e 's/^ *\(.*[^ ]\) *# in file \(.*\)/\2: \1/p'
-
RDOCBENCHOUT=/tmp/rdocbench
GCBENCH_ITEM=null
@@ -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,19 +784,17 @@ $(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 $@
$(Q) $(CPP) -DRUBY_EXPORT $(INCFLAGS) $(CPPFLAGS) "$(srcdir)/version.c" | \
$(BOOTSTRAPRUBY) "$(tooldir)/generic_erb.rb" -o $@ "$(srcdir)/template/fake.rb.in" \
- i=- srcdir="$(srcdir)" BASERUBY="$(BASERUBY)" \
- LIBPATHENV="$(LIBPATHENV)" PRELOADENV="$(PRELOADENV)" LIBRUBY_SO="$(LIBRUBY_SO)"
+ i=- srcdir="$(srcdir)" BASERUBY="$(BASERUBY)"
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 +802,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 +809,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,17 +847,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
-
-PRECHECK_TEST_ALL = yes-test-all-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: $(PRECHECK_TEST_ALL)
+yes-test-all: programs PHONY
$(ACTIONS_GROUP)
$(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TEST_EXCLUDES) $(TESTOPTS) $(TESTS)
$(ACTIONS_ENDGROUP)
@@ -982,14 +892,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:
@@ -1033,19 +942,23 @@ $(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)
@$(NULLCMD) > $@
-exe/$(PROGRAM): $(TIMESTAMPDIR)/$(arch)/.time
exe/$(PROGRAM): ruby-runner.c ruby-runner.h exe/.time $(PREP) {$(VPATH)}config.h
$(Q) $(CC) $(CFLAGS) $(INCFLAGS) $(CPPFLAGS) -DRUBY_INSTALL_NAME=$(@F) $(COUTFLAG)ruby-runner.$(OBJEXT) -c $(CSRCFLAG)$(srcdir)/ruby-runner.c
$(Q) $(PURIFY) $(CC) $(CFLAGS) $(LDFLAGS) $(OUTFLAG)$@ ruby-runner.$(OBJEXT) $(LIBS)
@@ -1058,8 +971,6 @@ exe/$(PROGRAM): ruby-runner.c ruby-runner.h exe/.time $(PREP) {$(VPATH)}config.h
-e ' File.symlink(prog, dest)' \
-e 'end' \
$(@F) $(@D) $(RUBY_INSTALL_NAME)$(EXEEXT)
- $(Q) $(BOOTSTRAPRUBY) -r$(srcdir)/lib/fileutils \
- -e 'FileUtils::Verbose.ln_sr(*ARGV, force: true)' rbconfig.rb $(EXTOUT)/$(arch)
exe/.time:
$(Q) $(MAKEDIRS) $(@D)
@@ -1127,7 +1038,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 \
@@ -1154,6 +1065,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)
@@ -1165,6 +1077,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 \
@@ -1173,8 +1086,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 \
@@ -1197,16 +1110,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
+srcs: common-srcs missing-srcs srcs-enc
-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
-
-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 \
@@ -1252,9 +1158,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 $@
@@ -1306,13 +1212,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
@@ -1323,20 +1225,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 $@
@@ -1364,7 +1259,7 @@ $(srcdir)/ext/rbconfig/sizeof/limits.c: $(srcdir)/ext/rbconfig/sizeof/depend \
$(exec) $(MAKE) -f - $(mflags) \
Q=$(Q) ECHO=$(ECHO) top_srcdir=../../.. srcdir=. VPATH=../../.. RUBY="$(BASERUBY)" $(@F)
-$(srcdir)/ext/socket/constdefs.c: $(srcdir)/ext/socket/depend $(srcdir)/ext/socket/mkconstants.rb
+$(srcdir)/ext/socket/constdefs.c: $(srcdir)/ext/socket/depend
$(Q) $(CHDIR) $(@D) && \
$(CAT_DEPEND) depend | \
$(exec) $(MAKE) -f - $(mflags) \
@@ -1426,10 +1321,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)
@@ -1452,7 +1346,7 @@ dist:
up:: update-remote
-up$(DOT_WAIT)::
+up::
-$(Q)$(MAKE) $(mflags) Q=$(Q) REVISION_FORCE=PHONY ALWAYS_UPDATE_UNICODE= after-update
yes::
@@ -1479,10 +1373,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)
@@ -1509,28 +1399,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)"
@@ -1560,7 +1436,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:5.1.0" "test-unit-rr"
+ --install-dir .bundle --conservative "bundler" "minitest:~> 5" "test-unit" "rake" "hoe" "yard" "pry" "packnga" "rexml" "json-schema" "test-unit-rr"
$(ACTIONS_ENDGROUP)
PREPARE_BUNDLED_GEMS = test-bundled-gems-prepare
@@ -1584,30 +1460,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)
@@ -1616,24 +1486,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])" \
@@ -1641,9 +1510,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:
@@ -1793,16 +1662,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
@@ -1845,8 +1704,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
@@ -1868,7 +1725,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 = ""
@@ -1889,16 +1746,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" \
@@ -1909,12 +1763,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
@@ -1946,7 +1800,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
@@ -1976,10 +1829,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
@@ -1992,7 +1841,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
@@ -2005,7 +1853,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
@@ -2063,7 +1910,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
@@ -2132,6 +1978,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
@@ -2162,6 +2009,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
@@ -2173,24 +2021,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
@@ -2203,34 +2044,12 @@ 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
ast.$(OBJEXT): $(top_srcdir)/internal/variable.h
ast.$(OBJEXT): $(top_srcdir)/internal/vm.h
ast.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-ast.$(OBJEXT): $(top_srcdir)/prism/defines.h
-ast.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-ast.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-ast.$(OBJEXT): $(top_srcdir)/prism/node.h
-ast.$(OBJEXT): $(top_srcdir)/prism/options.h
-ast.$(OBJEXT): $(top_srcdir)/prism/pack.h
-ast.$(OBJEXT): $(top_srcdir)/prism/parser.h
-ast.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-ast.$(OBJEXT): $(top_srcdir)/prism/prism.h
-ast.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
ast.$(OBJEXT): {$(VPATH)}assert.h
ast.$(OBJEXT): {$(VPATH)}ast.c
ast.$(OBJEXT): {$(VPATH)}ast.rbinc
@@ -2291,7 +2110,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
@@ -2360,6 +2178,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
@@ -2390,6 +2209,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
@@ -2407,12 +2227,8 @@ ast.$(OBJEXT): {$(VPATH)}missing.h
ast.$(OBJEXT): {$(VPATH)}node.h
ast.$(OBJEXT): {$(VPATH)}onigmo.h
ast.$(OBJEXT): {$(VPATH)}oniguruma.h
-ast.$(OBJEXT): {$(VPATH)}prism/ast.h
-ast.$(OBJEXT): {$(VPATH)}prism/version.h
-ast.$(OBJEXT): {$(VPATH)}prism_compile.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
@@ -2421,13 +2237,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
@@ -2435,7 +2245,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
@@ -2445,7 +2254,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
@@ -2459,7 +2267,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
@@ -2502,7 +2309,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
@@ -2535,15 +2341,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
@@ -2571,6 +2368,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
@@ -2601,6 +2399,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
@@ -2612,23 +2411,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
@@ -2644,27 +2433,6 @@ builtin.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
builtin.$(OBJEXT): $(top_srcdir)/internal/variable.h
builtin.$(OBJEXT): $(top_srcdir)/internal/vm.h
builtin.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/defines.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/node.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/options.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/pack.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/parser.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/prism.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
builtin.$(OBJEXT): {$(VPATH)}assert.h
builtin.$(OBJEXT): {$(VPATH)}atomic.h
builtin.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -2682,7 +2450,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
@@ -2725,7 +2492,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
@@ -2758,15 +2524,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
@@ -2794,6 +2551,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
@@ -2824,6 +2582,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
@@ -2839,14 +2598,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)}prism/ast.h
-builtin.$(OBJEXT): {$(VPATH)}prism/version.h
-builtin.$(OBJEXT): {$(VPATH)}prism_compile.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
@@ -2933,7 +2686,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
@@ -3002,6 +2754,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
@@ -3032,6 +2785,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
@@ -3050,18 +2804,14 @@ 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
class.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
class.$(OBJEXT): {$(VPATH)}thread_native.h
class.$(OBJEXT): {$(VPATH)}vm_core.h
-class.$(OBJEXT): {$(VPATH)}vm_debug.h
class.$(OBJEXT): {$(VPATH)}vm_opts.h
-class.$(OBJEXT): {$(VPATH)}vm_sync.h
compar.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-compar.$(OBJEXT): $(hdrdir)/ruby/version.h
compar.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
compar.$(OBJEXT): $(top_srcdir)/internal/compar.h
compar.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -3125,7 +2875,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
@@ -3194,6 +2943,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
@@ -3224,6 +2974,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
@@ -3245,7 +2996,6 @@ compile.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
compile.$(OBJEXT): $(CCAN_DIR)/list/list.h
compile.$(OBJEXT): $(CCAN_DIR)/str/str.h
compile.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-compile.$(OBJEXT): $(hdrdir)/ruby/version.h
compile.$(OBJEXT): $(top_srcdir)/internal/array.h
compile.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
compile.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -3272,28 +3022,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/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
@@ -3313,6 +3041,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
@@ -3358,7 +3087,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
@@ -3428,6 +3156,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
@@ -3458,6 +3187,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
@@ -3476,16 +3206,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
@@ -3496,15 +3220,8 @@ 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)}vm_sync.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
-complex.$(OBJEXT): $(CCAN_DIR)/str/str.h
complex.$(OBJEXT): $(hdrdir)/ruby/ruby.h
complex.$(OBJEXT): $(top_srcdir)/internal/array.h
-complex.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
complex.$(OBJEXT): $(top_srcdir)/internal/bignum.h
complex.$(OBJEXT): $(top_srcdir)/internal/bits.h
complex.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -3512,19 +3229,16 @@ complex.$(OBJEXT): $(top_srcdir)/internal/compilers.h
complex.$(OBJEXT): $(top_srcdir)/internal/complex.h
complex.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
complex.$(OBJEXT): $(top_srcdir)/internal/gc.h
-complex.$(OBJEXT): $(top_srcdir)/internal/imemo.h
complex.$(OBJEXT): $(top_srcdir)/internal/math.h
complex.$(OBJEXT): $(top_srcdir)/internal/numeric.h
complex.$(OBJEXT): $(top_srcdir)/internal/object.h
complex.$(OBJEXT): $(top_srcdir)/internal/rational.h
complex.$(OBJEXT): $(top_srcdir)/internal/serial.h
complex.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-complex.$(OBJEXT): $(top_srcdir)/internal/string.h
complex.$(OBJEXT): $(top_srcdir)/internal/variable.h
complex.$(OBJEXT): $(top_srcdir)/internal/vm.h
complex.$(OBJEXT): $(top_srcdir)/internal/warnings.h
complex.$(OBJEXT): {$(VPATH)}assert.h
-complex.$(OBJEXT): {$(VPATH)}atomic.h
complex.$(OBJEXT): {$(VPATH)}backward/2/assume.h
complex.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
complex.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -3537,9 +3251,7 @@ complex.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
complex.$(OBJEXT): {$(VPATH)}complex.c
complex.$(OBJEXT): {$(VPATH)}config.h
complex.$(OBJEXT): {$(VPATH)}constant.h
-complex.$(OBJEXT): {$(VPATH)}debug_counter.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
@@ -3582,7 +3294,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
@@ -3615,15 +3326,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
@@ -3651,6 +3353,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
@@ -3681,6 +3384,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
@@ -3692,30 +3396,17 @@ complex.$(OBJEXT): {$(VPATH)}internal/value_type.h
complex.$(OBJEXT): {$(VPATH)}internal/variable.h
complex.$(OBJEXT): {$(VPATH)}internal/warning_push.h
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
-complex.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-complex.$(OBJEXT): {$(VPATH)}thread_native.h
-complex.$(OBJEXT): {$(VPATH)}vm_core.h
-complex.$(OBJEXT): {$(VPATH)}vm_debug.h
-complex.$(OBJEXT): {$(VPATH)}vm_opts.h
-complex.$(OBJEXT): {$(VPATH)}vm_sync.h
cont.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
cont.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
cont.$(OBJEXT): $(CCAN_DIR)/list/list.h
cont.$(OBJEXT): $(CCAN_DIR)/str/str.h
cont.$(OBJEXT): $(hdrdir)/ruby.h
cont.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-cont.$(OBJEXT): $(hdrdir)/ruby/version.h
cont.$(OBJEXT): $(top_srcdir)/internal/array.h
cont.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
cont.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -3728,31 +3419,9 @@ 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
-cont.$(OBJEXT): $(top_srcdir)/prism/defines.h
-cont.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-cont.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-cont.$(OBJEXT): $(top_srcdir)/prism/node.h
-cont.$(OBJEXT): $(top_srcdir)/prism/options.h
-cont.$(OBJEXT): $(top_srcdir)/prism/pack.h
-cont.$(OBJEXT): $(top_srcdir)/prism/parser.h
-cont.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-cont.$(OBJEXT): $(top_srcdir)/prism/prism.h
-cont.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
cont.$(OBJEXT): {$(VPATH)}$(COROUTINE_H)
cont.$(OBJEXT): {$(VPATH)}assert.h
cont.$(OBJEXT): {$(VPATH)}atomic.h
@@ -3773,6 +3442,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
@@ -3815,7 +3485,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
@@ -3884,6 +3553,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
@@ -3914,6 +3584,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
@@ -3928,18 +3599,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)}prism/ast.h
-cont.$(OBJEXT): {$(VPATH)}prism/version.h
-cont.$(OBJEXT): {$(VPATH)}prism_compile.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
@@ -3986,6 +3653,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
@@ -4028,7 +3696,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
@@ -4097,6 +3764,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
@@ -4127,6 +3795,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
@@ -4148,7 +3817,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
@@ -4160,7 +3828,6 @@ debug.$(OBJEXT): {$(VPATH)}vm_callinfo.h
debug.$(OBJEXT): {$(VPATH)}vm_core.h
debug.$(OBJEXT): {$(VPATH)}vm_debug.h
debug.$(OBJEXT): {$(VPATH)}vm_opts.h
-debug.$(OBJEXT): {$(VPATH)}vm_sync.h
debug_counter.$(OBJEXT): $(hdrdir)/ruby/ruby.h
debug_counter.$(OBJEXT): {$(VPATH)}assert.h
debug_counter.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -4215,7 +3882,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
@@ -4275,6 +3941,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
@@ -4305,6 +3972,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
@@ -4320,14 +3988,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): $(hdrdir)/ruby/version.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
@@ -4335,7 +3997,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
@@ -4345,7 +4006,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
@@ -4405,7 +4065,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
@@ -4474,6 +4133,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
@@ -4504,6 +4164,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
@@ -4516,23 +4177,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
@@ -4590,7 +4242,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
@@ -4650,6 +4301,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
@@ -4680,6 +4332,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
@@ -4747,7 +4400,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
@@ -4807,6 +4459,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
@@ -4837,6 +4490,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
@@ -4903,7 +4557,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
@@ -4963,6 +4616,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
@@ -4993,6 +4647,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
@@ -5130,6 +4785,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
@@ -5160,6 +4816,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
@@ -5287,6 +4944,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
@@ -5317,6 +4975,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
@@ -5444,6 +5103,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
@@ -5474,6 +5134,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
@@ -5612,6 +5273,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
@@ -5642,6 +5304,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
@@ -5780,6 +5443,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
@@ -5810,6 +5474,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
@@ -5827,22 +5492,14 @@ enc/utf_8.$(OBJEXT): {$(VPATH)}oniguruma.h
enc/utf_8.$(OBJEXT): {$(VPATH)}regenc.h
enc/utf_8.$(OBJEXT): {$(VPATH)}st.h
enc/utf_8.$(OBJEXT): {$(VPATH)}subst.h
-encoding.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-encoding.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-encoding.$(OBJEXT): $(CCAN_DIR)/list/list.h
-encoding.$(OBJEXT): $(CCAN_DIR)/str/str.h
encoding.$(OBJEXT): $(hdrdir)/ruby.h
encoding.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-encoding.$(OBJEXT): $(hdrdir)/ruby/version.h
-encoding.$(OBJEXT): $(top_srcdir)/internal/array.h
-encoding.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
encoding.$(OBJEXT): $(top_srcdir)/internal/class.h
encoding.$(OBJEXT): $(top_srcdir)/internal/compilers.h
encoding.$(OBJEXT): $(top_srcdir)/internal/enc.h
encoding.$(OBJEXT): $(top_srcdir)/internal/encoding.h
encoding.$(OBJEXT): $(top_srcdir)/internal/error.h
encoding.$(OBJEXT): $(top_srcdir)/internal/gc.h
-encoding.$(OBJEXT): $(top_srcdir)/internal/imemo.h
encoding.$(OBJEXT): $(top_srcdir)/internal/inits.h
encoding.$(OBJEXT): $(top_srcdir)/internal/load.h
encoding.$(OBJEXT): $(top_srcdir)/internal/object.h
@@ -5853,7 +5510,6 @@ encoding.$(OBJEXT): $(top_srcdir)/internal/variable.h
encoding.$(OBJEXT): $(top_srcdir)/internal/vm.h
encoding.$(OBJEXT): $(top_srcdir)/internal/warnings.h
encoding.$(OBJEXT): {$(VPATH)}assert.h
-encoding.$(OBJEXT): {$(VPATH)}atomic.h
encoding.$(OBJEXT): {$(VPATH)}backward/2/assume.h
encoding.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
encoding.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -5870,7 +5526,6 @@ encoding.$(OBJEXT): {$(VPATH)}defines.h
encoding.$(OBJEXT): {$(VPATH)}encindex.h
encoding.$(OBJEXT): {$(VPATH)}encoding.c
encoding.$(OBJEXT): {$(VPATH)}encoding.h
-encoding.$(OBJEXT): {$(VPATH)}id.h
encoding.$(OBJEXT): {$(VPATH)}id_table.h
encoding.$(OBJEXT): {$(VPATH)}intern.h
encoding.$(OBJEXT): {$(VPATH)}internal.h
@@ -5912,7 +5567,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
@@ -5981,6 +5635,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
@@ -6011,6 +5666,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
@@ -6022,24 +5678,16 @@ encoding.$(OBJEXT): {$(VPATH)}internal/value_type.h
encoding.$(OBJEXT): {$(VPATH)}internal/variable.h
encoding.$(OBJEXT): {$(VPATH)}internal/warning_push.h
encoding.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-encoding.$(OBJEXT): {$(VPATH)}method.h
encoding.$(OBJEXT): {$(VPATH)}missing.h
-encoding.$(OBJEXT): {$(VPATH)}node.h
encoding.$(OBJEXT): {$(VPATH)}onigmo.h
encoding.$(OBJEXT): {$(VPATH)}oniguruma.h
encoding.$(OBJEXT): {$(VPATH)}regenc.h
encoding.$(OBJEXT): {$(VPATH)}ruby_assert.h
-encoding.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-encoding.$(OBJEXT): {$(VPATH)}rubyparser.h
encoding.$(OBJEXT): {$(VPATH)}shape.h
encoding.$(OBJEXT): {$(VPATH)}st.h
encoding.$(OBJEXT): {$(VPATH)}subst.h
-encoding.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-encoding.$(OBJEXT): {$(VPATH)}thread_native.h
encoding.$(OBJEXT): {$(VPATH)}util.h
-encoding.$(OBJEXT): {$(VPATH)}vm_core.h
encoding.$(OBJEXT): {$(VPATH)}vm_debug.h
-encoding.$(OBJEXT): {$(VPATH)}vm_opts.h
encoding.$(OBJEXT): {$(VPATH)}vm_sync.h
enum.$(OBJEXT): $(hdrdir)/ruby/ruby.h
enum.$(OBJEXT): $(top_srcdir)/internal/array.h
@@ -6121,7 +5769,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
@@ -6190,6 +5837,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
@@ -6220,6 +5868,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
@@ -6240,14 +5889,8 @@ enum.$(OBJEXT): {$(VPATH)}st.h
enum.$(OBJEXT): {$(VPATH)}subst.h
enum.$(OBJEXT): {$(VPATH)}symbol.h
enum.$(OBJEXT): {$(VPATH)}util.h
-enumerator.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-enumerator.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-enumerator.$(OBJEXT): $(CCAN_DIR)/list/list.h
-enumerator.$(OBJEXT): $(CCAN_DIR)/str/str.h
enumerator.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-enumerator.$(OBJEXT): $(hdrdir)/ruby/version.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/array.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/bignum.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/bits.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -6265,11 +5908,9 @@ 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
-enumerator.$(OBJEXT): {$(VPATH)}atomic.h
enumerator.$(OBJEXT): {$(VPATH)}backward/2/assume.h
enumerator.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
enumerator.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -6280,8 +5921,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)}debug_counter.h
enumerator.$(OBJEXT): {$(VPATH)}defines.h
enumerator.$(OBJEXT): {$(VPATH)}encoding.h
enumerator.$(OBJEXT): {$(VPATH)}enumerator.c
@@ -6327,7 +5966,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
@@ -6396,6 +6034,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
@@ -6426,6 +6065,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
@@ -6437,29 +6077,18 @@ enumerator.$(OBJEXT): {$(VPATH)}internal/value_type.h
enumerator.$(OBJEXT): {$(VPATH)}internal/variable.h
enumerator.$(OBJEXT): {$(VPATH)}internal/warning_push.h
enumerator.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-enumerator.$(OBJEXT): {$(VPATH)}method.h
enumerator.$(OBJEXT): {$(VPATH)}missing.h
-enumerator.$(OBJEXT): {$(VPATH)}node.h
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
-enumerator.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-enumerator.$(OBJEXT): {$(VPATH)}thread_native.h
-enumerator.$(OBJEXT): {$(VPATH)}vm_core.h
-enumerator.$(OBJEXT): {$(VPATH)}vm_debug.h
-enumerator.$(OBJEXT): {$(VPATH)}vm_opts.h
-enumerator.$(OBJEXT): {$(VPATH)}vm_sync.h
error.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
error.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
error.$(OBJEXT): $(CCAN_DIR)/list/list.h
error.$(OBJEXT): $(CCAN_DIR)/str/str.h
error.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-error.$(OBJEXT): $(hdrdir)/ruby/version.h
error.$(OBJEXT): $(top_srcdir)/internal/array.h
error.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
error.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -6472,7 +6101,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
@@ -6540,7 +6168,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
@@ -6609,6 +6236,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
@@ -6639,6 +6267,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
@@ -6659,13 +6288,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
@@ -6675,7 +6302,6 @@ eval.$(OBJEXT): $(CCAN_DIR)/list/list.h
eval.$(OBJEXT): $(CCAN_DIR)/str/str.h
eval.$(OBJEXT): $(hdrdir)/ruby.h
eval.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-eval.$(OBJEXT): $(hdrdir)/ruby/version.h
eval.$(OBJEXT): $(top_srcdir)/internal/array.h
eval.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
eval.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -6696,27 +6322,6 @@ eval.$(OBJEXT): $(top_srcdir)/internal/thread.h
eval.$(OBJEXT): $(top_srcdir)/internal/variable.h
eval.$(OBJEXT): $(top_srcdir)/internal/vm.h
eval.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-eval.$(OBJEXT): $(top_srcdir)/prism/defines.h
-eval.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-eval.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-eval.$(OBJEXT): $(top_srcdir)/prism/node.h
-eval.$(OBJEXT): $(top_srcdir)/prism/options.h
-eval.$(OBJEXT): $(top_srcdir)/prism/pack.h
-eval.$(OBJEXT): $(top_srcdir)/prism/parser.h
-eval.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-eval.$(OBJEXT): $(top_srcdir)/prism/prism.h
-eval.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
eval.$(OBJEXT): {$(VPATH)}assert.h
eval.$(OBJEXT): {$(VPATH)}atomic.h
eval.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -6738,6 +6343,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
@@ -6780,7 +6386,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
@@ -6849,6 +6454,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
@@ -6879,6 +6485,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
@@ -6894,21 +6501,17 @@ 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
-eval.$(OBJEXT): {$(VPATH)}prism/ast.h
-eval.$(OBJEXT): {$(VPATH)}prism/version.h
-eval.$(OBJEXT): {$(VPATH)}prism_compile.h
eval.$(OBJEXT): {$(VPATH)}probes.dmyh
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
@@ -6918,7 +6521,6 @@ eval.$(OBJEXT): {$(VPATH)}vm.h
eval.$(OBJEXT): {$(VPATH)}vm_core.h
eval.$(OBJEXT): {$(VPATH)}vm_debug.h
eval.$(OBJEXT): {$(VPATH)}vm_opts.h
-eval.$(OBJEXT): {$(VPATH)}vm_sync.h
explicit_bzero.$(OBJEXT): {$(VPATH)}config.h
explicit_bzero.$(OBJEXT): {$(VPATH)}explicit_bzero.c
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/attr/format.h
@@ -6934,12 +6536,7 @@ 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): $(hdrdir)/ruby/version.h
file.$(OBJEXT): $(top_srcdir)/internal/array.h
file.$(OBJEXT): $(top_srcdir)/internal/class.h
file.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -7018,7 +6615,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
@@ -7087,6 +6683,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
@@ -7117,6 +6714,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
@@ -7136,7 +6734,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
@@ -7144,13 +6741,11 @@ gc.$(OBJEXT): $(CCAN_DIR)/list/list.h
gc.$(OBJEXT): $(CCAN_DIR)/str/str.h
gc.$(OBJEXT): $(hdrdir)/ruby.h
gc.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-gc.$(OBJEXT): $(hdrdir)/ruby/version.h
gc.$(OBJEXT): $(top_srcdir)/internal/array.h
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
@@ -7175,27 +6770,6 @@ gc.$(OBJEXT): $(top_srcdir)/internal/thread.h
gc.$(OBJEXT): $(top_srcdir)/internal/variable.h
gc.$(OBJEXT): $(top_srcdir)/internal/vm.h
gc.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-gc.$(OBJEXT): $(top_srcdir)/prism/defines.h
-gc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-gc.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-gc.$(OBJEXT): $(top_srcdir)/prism/node.h
-gc.$(OBJEXT): $(top_srcdir)/prism/options.h
-gc.$(OBJEXT): $(top_srcdir)/prism/pack.h
-gc.$(OBJEXT): $(top_srcdir)/prism/parser.h
-gc.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-gc.$(OBJEXT): $(top_srcdir)/prism/prism.h
-gc.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
gc.$(OBJEXT): {$(VPATH)}assert.h
gc.$(OBJEXT): {$(VPATH)}atomic.h
gc.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -7210,13 +6784,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
@@ -7260,7 +6834,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
@@ -7330,6 +6903,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
@@ -7360,6 +6934,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
@@ -7375,12 +6950,10 @@ 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
-gc.$(OBJEXT): {$(VPATH)}prism/ast.h
-gc.$(OBJEXT): {$(VPATH)}prism/version.h
-gc.$(OBJEXT): {$(VPATH)}prism_compile.h
gc.$(OBJEXT): {$(VPATH)}probes.dmyh
gc.$(OBJEXT): {$(VPATH)}probes.h
gc.$(OBJEXT): {$(VPATH)}ractor.h
@@ -7389,10 +6962,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
@@ -7400,6 +6971,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
@@ -7417,33 +6989,11 @@ 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
goruby.$(OBJEXT): $(top_srcdir)/internal/vm.h
goruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/defines.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/node.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/options.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/pack.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/parser.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/prism.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
goruby.$(OBJEXT): {$(VPATH)}assert.h
goruby.$(OBJEXT): {$(VPATH)}atomic.h
goruby.$(OBJEXT): {$(VPATH)}backward.h
@@ -7459,7 +7009,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
@@ -7504,7 +7053,6 @@ 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/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
@@ -7537,15 +7085,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
@@ -7573,6 +7112,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
@@ -7603,6 +7143,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
@@ -7619,14 +7160,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)}prism/ast.h
-goruby.$(OBJEXT): {$(VPATH)}prism/version.h
-goruby.$(OBJEXT): {$(VPATH)}prism_compile.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
@@ -7640,7 +7175,6 @@ hash.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
hash.$(OBJEXT): $(CCAN_DIR)/list/list.h
hash.$(OBJEXT): $(CCAN_DIR)/str/str.h
hash.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-hash.$(OBJEXT): $(hdrdir)/ruby/version.h
hash.$(OBJEXT): $(top_srcdir)/internal/array.h
hash.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
hash.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -7663,27 +7197,6 @@ hash.$(OBJEXT): $(top_srcdir)/internal/time.h
hash.$(OBJEXT): $(top_srcdir)/internal/variable.h
hash.$(OBJEXT): $(top_srcdir)/internal/vm.h
hash.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-hash.$(OBJEXT): $(top_srcdir)/prism/defines.h
-hash.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-hash.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-hash.$(OBJEXT): $(top_srcdir)/prism/node.h
-hash.$(OBJEXT): $(top_srcdir)/prism/options.h
-hash.$(OBJEXT): $(top_srcdir)/prism/pack.h
-hash.$(OBJEXT): $(top_srcdir)/prism/parser.h
-hash.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-hash.$(OBJEXT): $(top_srcdir)/prism/prism.h
-hash.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
hash.$(OBJEXT): {$(VPATH)}assert.h
hash.$(OBJEXT): {$(VPATH)}atomic.h
hash.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -7743,7 +7256,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
@@ -7812,6 +7324,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
@@ -7842,6 +7355,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
@@ -7859,21 +7373,18 @@ hash.$(OBJEXT): {$(VPATH)}missing.h
hash.$(OBJEXT): {$(VPATH)}node.h
hash.$(OBJEXT): {$(VPATH)}onigmo.h
hash.$(OBJEXT): {$(VPATH)}oniguruma.h
-hash.$(OBJEXT): {$(VPATH)}prism/ast.h
-hash.$(OBJEXT): {$(VPATH)}prism/version.h
-hash.$(OBJEXT): {$(VPATH)}prism_compile.h
hash.$(OBJEXT): {$(VPATH)}probes.dmyh
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
@@ -7937,7 +7448,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
@@ -7997,6 +7507,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
@@ -8027,6 +7538,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
@@ -8047,7 +7559,6 @@ io.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
io.$(OBJEXT): $(CCAN_DIR)/list/list.h
io.$(OBJEXT): $(CCAN_DIR)/str/str.h
io.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-io.$(OBJEXT): $(hdrdir)/ruby/version.h
io.$(OBJEXT): $(top_srcdir)/internal/array.h
io.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
io.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -8133,7 +7644,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
@@ -8202,6 +7712,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
@@ -8232,6 +7743,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
@@ -8255,7 +7767,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
@@ -8265,12 +7776,7 @@ 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): $(hdrdir)/ruby/version.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/array.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/bignum.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/bits.h
@@ -8337,7 +7843,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
@@ -8406,6 +7911,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
@@ -8436,6 +7942,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
@@ -8455,14 +7962,12 @@ 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
iseq.$(OBJEXT): $(CCAN_DIR)/str/str.h
iseq.$(OBJEXT): $(hdrdir)/ruby.h
iseq.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-iseq.$(OBJEXT): $(hdrdir)/ruby/version.h
iseq.$(OBJEXT): $(top_srcdir)/internal/array.h
iseq.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
iseq.$(OBJEXT): $(top_srcdir)/internal/bits.h
@@ -8475,7 +7980,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
@@ -8485,27 +7989,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/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
@@ -8524,6 +8007,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
@@ -8569,7 +8053,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
@@ -8638,6 +8121,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
@@ -8668,6 +8152,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
@@ -8683,18 +8168,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
@@ -8703,29 +8184,23 @@ iseq.$(OBJEXT): {$(VPATH)}thread_native.h
iseq.$(OBJEXT): {$(VPATH)}util.h
iseq.$(OBJEXT): {$(VPATH)}vm_callinfo.h
iseq.$(OBJEXT): {$(VPATH)}vm_core.h
-iseq.$(OBJEXT): {$(VPATH)}vm_debug.h
iseq.$(OBJEXT): {$(VPATH)}vm_opts.h
-iseq.$(OBJEXT): {$(VPATH)}vm_sync.h
iseq.$(OBJEXT): {$(VPATH)}yjit.h
load.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
load.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
load.$(OBJEXT): $(CCAN_DIR)/list/list.h
load.$(OBJEXT): $(CCAN_DIR)/str/str.h
load.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-load.$(OBJEXT): $(hdrdir)/ruby/version.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
load.$(OBJEXT): $(top_srcdir)/internal/file.h
load.$(OBJEXT): $(top_srcdir)/internal/gc.h
-load.$(OBJEXT): $(top_srcdir)/internal/hash.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
@@ -8733,27 +8208,6 @@ load.$(OBJEXT): $(top_srcdir)/internal/thread.h
load.$(OBJEXT): $(top_srcdir)/internal/variable.h
load.$(OBJEXT): $(top_srcdir)/internal/vm.h
load.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-load.$(OBJEXT): $(top_srcdir)/prism/defines.h
-load.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-load.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-load.$(OBJEXT): $(top_srcdir)/prism/node.h
-load.$(OBJEXT): $(top_srcdir)/prism/options.h
-load.$(OBJEXT): $(top_srcdir)/prism/pack.h
-load.$(OBJEXT): $(top_srcdir)/prism/parser.h
-load.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-load.$(OBJEXT): $(top_srcdir)/prism/prism.h
-load.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
load.$(OBJEXT): {$(VPATH)}assert.h
load.$(OBJEXT): {$(VPATH)}atomic.h
load.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -8814,7 +8268,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
@@ -8883,6 +8336,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
@@ -8913,6 +8367,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
@@ -8931,14 +8386,10 @@ load.$(OBJEXT): {$(VPATH)}missing.h
load.$(OBJEXT): {$(VPATH)}node.h
load.$(OBJEXT): {$(VPATH)}onigmo.h
load.$(OBJEXT): {$(VPATH)}oniguruma.h
-load.$(OBJEXT): {$(VPATH)}prism/ast.h
-load.$(OBJEXT): {$(VPATH)}prism/version.h
-load.$(OBJEXT): {$(VPATH)}prism_compile.h
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
@@ -9000,7 +8451,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
@@ -9060,6 +8510,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
@@ -9090,6 +8541,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
@@ -9160,7 +8612,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
@@ -9229,6 +8680,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
@@ -9259,6 +8711,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
@@ -9329,7 +8782,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
@@ -9389,6 +8841,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
@@ -9419,6 +8872,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
@@ -9435,14 +8889,8 @@ main.$(OBJEXT): {$(VPATH)}missing.h
main.$(OBJEXT): {$(VPATH)}st.h
main.$(OBJEXT): {$(VPATH)}subst.h
main.$(OBJEXT): {$(VPATH)}vm_debug.h
-marshal.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-marshal.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-marshal.$(OBJEXT): $(CCAN_DIR)/list/list.h
-marshal.$(OBJEXT): $(CCAN_DIR)/str/str.h
marshal.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-marshal.$(OBJEXT): $(hdrdir)/ruby/version.h
marshal.$(OBJEXT): $(top_srcdir)/internal/array.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
marshal.$(OBJEXT): $(top_srcdir)/internal/bignum.h
marshal.$(OBJEXT): $(top_srcdir)/internal/bits.h
marshal.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -9452,7 +8900,6 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/error.h
marshal.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
marshal.$(OBJEXT): $(top_srcdir)/internal/gc.h
marshal.$(OBJEXT): $(top_srcdir)/internal/hash.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/imemo.h
marshal.$(OBJEXT): $(top_srcdir)/internal/numeric.h
marshal.$(OBJEXT): $(top_srcdir)/internal/object.h
marshal.$(OBJEXT): $(top_srcdir)/internal/serial.h
@@ -9465,7 +8912,6 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/variable.h
marshal.$(OBJEXT): $(top_srcdir)/internal/vm.h
marshal.$(OBJEXT): $(top_srcdir)/internal/warnings.h
marshal.$(OBJEXT): {$(VPATH)}assert.h
-marshal.$(OBJEXT): {$(VPATH)}atomic.h
marshal.$(OBJEXT): {$(VPATH)}backward/2/assume.h
marshal.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
marshal.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -9478,11 +8924,9 @@ marshal.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
marshal.$(OBJEXT): {$(VPATH)}builtin.h
marshal.$(OBJEXT): {$(VPATH)}config.h
marshal.$(OBJEXT): {$(VPATH)}constant.h
-marshal.$(OBJEXT): {$(VPATH)}debug_counter.h
marshal.$(OBJEXT): {$(VPATH)}defines.h
marshal.$(OBJEXT): {$(VPATH)}encindex.h
marshal.$(OBJEXT): {$(VPATH)}encoding.h
-marshal.$(OBJEXT): {$(VPATH)}id.h
marshal.$(OBJEXT): {$(VPATH)}id_table.h
marshal.$(OBJEXT): {$(VPATH)}intern.h
marshal.$(OBJEXT): {$(VPATH)}internal.h
@@ -9524,7 +8968,6 @@ 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/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
@@ -9593,6 +9036,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
@@ -9623,6 +9067,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
@@ -9637,24 +9082,13 @@ marshal.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
marshal.$(OBJEXT): {$(VPATH)}io.h
marshal.$(OBJEXT): {$(VPATH)}marshal.c
marshal.$(OBJEXT): {$(VPATH)}marshal.rbinc
-marshal.$(OBJEXT): {$(VPATH)}method.h
marshal.$(OBJEXT): {$(VPATH)}missing.h
-marshal.$(OBJEXT): {$(VPATH)}node.h
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
-marshal.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-marshal.$(OBJEXT): {$(VPATH)}thread_native.h
marshal.$(OBJEXT): {$(VPATH)}util.h
-marshal.$(OBJEXT): {$(VPATH)}vm_core.h
-marshal.$(OBJEXT): {$(VPATH)}vm_debug.h
-marshal.$(OBJEXT): {$(VPATH)}vm_opts.h
-marshal.$(OBJEXT): {$(VPATH)}vm_sync.h
math.$(OBJEXT): $(hdrdir)/ruby/ruby.h
math.$(OBJEXT): $(top_srcdir)/internal/bignum.h
math.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -9722,7 +9156,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
@@ -9782,6 +9215,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
@@ -9812,6 +9246,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
@@ -9828,24 +9263,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
@@ -9859,8 +9283,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
@@ -9902,7 +9324,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
@@ -9935,15 +9356,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
@@ -9971,6 +9383,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
@@ -10001,6 +9414,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
@@ -10014,62 +9428,29 @@ 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
miniinit.$(OBJEXT): $(top_srcdir)/internal/vm.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/defines.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/node.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/options.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/pack.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/parser.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/prism.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
miniinit.$(OBJEXT): {$(VPATH)}array.rb
miniinit.$(OBJEXT): {$(VPATH)}assert.h
miniinit.$(OBJEXT): {$(VPATH)}ast.rb
@@ -10133,7 +9514,6 @@ 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/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
@@ -10202,6 +9582,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
@@ -10232,6 +9613,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
@@ -10252,6 +9634,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
@@ -10259,15 +9643,9 @@ miniinit.$(OBJEXT): {$(VPATH)}onigmo.h
miniinit.$(OBJEXT): {$(VPATH)}oniguruma.h
miniinit.$(OBJEXT): {$(VPATH)}pack.rb
miniinit.$(OBJEXT): {$(VPATH)}prelude.rb
-miniinit.$(OBJEXT): {$(VPATH)}prism/ast.h
-miniinit.$(OBJEXT): {$(VPATH)}prism/version.h
-miniinit.$(OBJEXT): {$(VPATH)}prism_compile.h
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
@@ -10281,6 +9659,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
@@ -10311,7 +10124,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
@@ -10354,7 +10166,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
@@ -10387,15 +10198,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
@@ -10423,6 +10225,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
@@ -10453,6 +10256,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
@@ -10468,12 +10272,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
@@ -10481,212 +10281,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
@@ -10696,7 +10292,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
@@ -10708,7 +10303,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
@@ -10765,7 +10359,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
@@ -10834,6 +10427,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
@@ -10864,6 +10458,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
@@ -10875,32 +10470,18 @@ 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
-object.$(OBJEXT): $(CCAN_DIR)/str/str.h
object.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-object.$(OBJEXT): $(hdrdir)/ruby/version.h
object.$(OBJEXT): $(top_srcdir)/internal/array.h
-object.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
object.$(OBJEXT): $(top_srcdir)/internal/bignum.h
object.$(OBJEXT): $(top_srcdir)/internal/bits.h
object.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -10909,7 +10490,6 @@ object.$(OBJEXT): $(top_srcdir)/internal/error.h
object.$(OBJEXT): $(top_srcdir)/internal/eval.h
object.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
object.$(OBJEXT): $(top_srcdir)/internal/gc.h
-object.$(OBJEXT): $(top_srcdir)/internal/imemo.h
object.$(OBJEXT): $(top_srcdir)/internal/inits.h
object.$(OBJEXT): $(top_srcdir)/internal/numeric.h
object.$(OBJEXT): $(top_srcdir)/internal/object.h
@@ -10922,7 +10502,6 @@ object.$(OBJEXT): $(top_srcdir)/internal/variable.h
object.$(OBJEXT): $(top_srcdir)/internal/vm.h
object.$(OBJEXT): $(top_srcdir)/internal/warnings.h
object.$(OBJEXT): {$(VPATH)}assert.h
-object.$(OBJEXT): {$(VPATH)}atomic.h
object.$(OBJEXT): {$(VPATH)}backward/2/assume.h
object.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
object.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -10935,7 +10514,6 @@ object.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
object.$(OBJEXT): {$(VPATH)}builtin.h
object.$(OBJEXT): {$(VPATH)}config.h
object.$(OBJEXT): {$(VPATH)}constant.h
-object.$(OBJEXT): {$(VPATH)}debug_counter.h
object.$(OBJEXT): {$(VPATH)}defines.h
object.$(OBJEXT): {$(VPATH)}encoding.h
object.$(OBJEXT): {$(VPATH)}id.h
@@ -10980,7 +10558,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
@@ -11049,6 +10626,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
@@ -11079,6 +10657,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
@@ -11091,49 +10670,29 @@ object.$(OBJEXT): {$(VPATH)}internal/variable.h
object.$(OBJEXT): {$(VPATH)}internal/warning_push.h
object.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
object.$(OBJEXT): {$(VPATH)}kernel.rbinc
-object.$(OBJEXT): {$(VPATH)}method.h
object.$(OBJEXT): {$(VPATH)}missing.h
object.$(OBJEXT): {$(VPATH)}nilclass.rbinc
-object.$(OBJEXT): {$(VPATH)}node.h
object.$(OBJEXT): {$(VPATH)}object.c
object.$(OBJEXT): {$(VPATH)}onigmo.h
object.$(OBJEXT): {$(VPATH)}oniguruma.h
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
-object.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-object.$(OBJEXT): {$(VPATH)}thread_native.h
object.$(OBJEXT): {$(VPATH)}util.h
object.$(OBJEXT): {$(VPATH)}variable.h
-object.$(OBJEXT): {$(VPATH)}vm_core.h
-object.$(OBJEXT): {$(VPATH)}vm_debug.h
-object.$(OBJEXT): {$(VPATH)}vm_opts.h
-object.$(OBJEXT): {$(VPATH)}vm_sync.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
@@ -11148,7 +10707,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
@@ -11190,7 +10748,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
@@ -11259,6 +10816,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
@@ -11289,6 +10847,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
@@ -11300,33 +10859,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): $(hdrdir)/ruby/version.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
@@ -11343,7 +10887,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
@@ -11353,7 +10896,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
@@ -11410,7 +10952,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
@@ -11479,6 +11020,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
@@ -11509,6 +11051,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
@@ -11522,7 +11065,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
@@ -11530,1059 +11072,22 @@ 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/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/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_constant_pool.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/diagnostic.$(OBJEXT): {$(VPATH)}config.h
-prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/encoding.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.c
-prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/encoding.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/encoding.$(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/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/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_strncasecmp.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/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): $(top_srcdir)/prism/util/pm_strncasecmp.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/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/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): $(top_srcdir)/prism/util/pm_strncasecmp.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/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/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): $(top_srcdir)/prism/util/pm_strncasecmp.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/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_strncasecmp.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/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
proc.$(OBJEXT): $(CCAN_DIR)/str/str.h
proc.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-proc.$(OBJEXT): $(hdrdir)/ruby/version.h
proc.$(OBJEXT): $(top_srcdir)/internal/array.h
proc.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
proc.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -12590,7 +11095,6 @@ 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
@@ -12601,27 +11105,6 @@ proc.$(OBJEXT): $(top_srcdir)/internal/symbol.h
proc.$(OBJEXT): $(top_srcdir)/internal/variable.h
proc.$(OBJEXT): $(top_srcdir)/internal/vm.h
proc.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-proc.$(OBJEXT): $(top_srcdir)/prism/defines.h
-proc.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-proc.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-proc.$(OBJEXT): $(top_srcdir)/prism/node.h
-proc.$(OBJEXT): $(top_srcdir)/prism/options.h
-proc.$(OBJEXT): $(top_srcdir)/prism/pack.h
-proc.$(OBJEXT): $(top_srcdir)/prism/parser.h
-proc.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-proc.$(OBJEXT): $(top_srcdir)/prism/prism.h
-proc.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
proc.$(OBJEXT): {$(VPATH)}assert.h
proc.$(OBJEXT): {$(VPATH)}atomic.h
proc.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -12635,10 +11118,10 @@ proc.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
proc.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
proc.$(OBJEXT): {$(VPATH)}config.h
proc.$(OBJEXT): {$(VPATH)}constant.h
-proc.$(OBJEXT): {$(VPATH)}debug_counter.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
@@ -12681,7 +11164,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
@@ -12750,6 +11232,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
@@ -12780,6 +11263,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
@@ -12797,22 +11281,16 @@ proc.$(OBJEXT): {$(VPATH)}missing.h
proc.$(OBJEXT): {$(VPATH)}node.h
proc.$(OBJEXT): {$(VPATH)}onigmo.h
proc.$(OBJEXT): {$(VPATH)}oniguruma.h
-proc.$(OBJEXT): {$(VPATH)}prism/ast.h
-proc.$(OBJEXT): {$(VPATH)}prism/version.h
-proc.$(OBJEXT): {$(VPATH)}prism_compile.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
proc.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
proc.$(OBJEXT): {$(VPATH)}thread_native.h
proc.$(OBJEXT): {$(VPATH)}vm_core.h
-proc.$(OBJEXT): {$(VPATH)}vm_debug.h
proc.$(OBJEXT): {$(VPATH)}vm_opts.h
-proc.$(OBJEXT): {$(VPATH)}vm_sync.h
proc.$(OBJEXT): {$(VPATH)}yjit.h
process.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
process.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
@@ -12820,7 +11298,6 @@ process.$(OBJEXT): $(CCAN_DIR)/list/list.h
process.$(OBJEXT): $(CCAN_DIR)/str/str.h
process.$(OBJEXT): $(hdrdir)/ruby.h
process.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-process.$(OBJEXT): $(hdrdir)/ruby/version.h
process.$(OBJEXT): $(top_srcdir)/internal/array.h
process.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
process.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -12834,7 +11311,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
@@ -12907,7 +11383,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
@@ -12976,6 +11451,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
@@ -13006,6 +11482,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
@@ -13020,15 +11497,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
@@ -13037,16 +11513,13 @@ 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
ractor.$(OBJEXT): $(CCAN_DIR)/str/str.h
ractor.$(OBJEXT): $(hdrdir)/ruby.h
ractor.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-ractor.$(OBJEXT): $(hdrdir)/ruby/version.h
ractor.$(OBJEXT): $(top_srcdir)/internal/array.h
ractor.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
ractor.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -13085,7 +11558,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
@@ -13128,7 +11601,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
@@ -13197,6 +11669,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
@@ -13227,6 +11700,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
@@ -13240,6 +11714,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
@@ -13247,35 +11722,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
@@ -13298,8 +11766,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
@@ -13341,7 +11807,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
@@ -13374,15 +11839,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
@@ -13410,6 +11866,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
@@ -13440,6 +11897,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
@@ -13451,29 +11909,18 @@ 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): $(hdrdir)/ruby/version.h
range.$(OBJEXT): $(top_srcdir)/internal/array.h
range.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
range.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -13547,7 +11994,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
@@ -13616,6 +12062,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
@@ -13646,6 +12093,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
@@ -13664,13 +12112,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
@@ -13678,7 +12121,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
@@ -13688,7 +12130,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
@@ -13701,7 +12142,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
@@ -13744,7 +12184,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
@@ -13777,15 +12216,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
@@ -13813,6 +12243,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
@@ -13843,6 +12274,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
@@ -13854,30 +12286,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
@@ -13893,10 +12310,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
@@ -13912,7 +12327,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
@@ -13954,7 +12368,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
@@ -14024,6 +12437,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
@@ -14054,6 +12468,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
@@ -14065,9 +12480,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
@@ -14075,17 +12488,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
@@ -14138,7 +12544,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
@@ -14198,6 +12603,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
@@ -14228,6 +12634,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
@@ -14299,7 +12706,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
@@ -14359,6 +12765,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
@@ -14389,6 +12796,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
@@ -14459,7 +12867,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
@@ -14519,6 +12926,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
@@ -14549,6 +12957,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
@@ -14619,7 +13028,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
@@ -14679,6 +13087,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
@@ -14709,6 +13118,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
@@ -14783,7 +13193,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
@@ -14843,6 +13252,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
@@ -14873,6 +13283,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
@@ -14944,7 +13355,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
@@ -15004,6 +13414,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
@@ -15034,6 +13445,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
@@ -15052,511 +13464,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): $(top_srcdir)/prism/defines.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/node.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/options.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/pack.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/parser.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/prism.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.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)}prism/ast.h
-rjit.$(OBJEXT): {$(VPATH)}prism/version.h
-rjit.$(OBJEXT): {$(VPATH)}prism_compile.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): $(top_srcdir)/prism/defines.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/node.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/options.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/pack.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/parser.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/prism.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.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)}prism/ast.h
-rjit_c.$(OBJEXT): {$(VPATH)}prism/version.h
-rjit_c.$(OBJEXT): {$(VPATH)}prism_compile.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_debug.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)}vm_sync.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
@@ -15593,35 +13500,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/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
@@ -15682,7 +13567,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
@@ -15751,6 +13635,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
@@ -15781,6 +13666,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
@@ -15796,17 +13682,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
@@ -15817,7 +13699,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
@@ -15892,7 +13773,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
@@ -15961,6 +13841,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
@@ -15991,6 +13872,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
@@ -16011,7 +13893,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
@@ -16072,7 +13953,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
@@ -16132,6 +14012,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
@@ -16162,6 +14043,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
@@ -16183,18 +14065,14 @@ shape.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
shape.$(OBJEXT): $(CCAN_DIR)/list/list.h
shape.$(OBJEXT): $(CCAN_DIR)/str/str.h
shape.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-shape.$(OBJEXT): $(hdrdir)/ruby/version.h
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/object.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
@@ -16215,6 +14093,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
@@ -16257,7 +14136,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
@@ -16326,6 +14204,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
@@ -16356,6 +14235,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
@@ -16374,7 +14254,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
@@ -16392,11 +14271,9 @@ signal.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
signal.$(OBJEXT): $(CCAN_DIR)/list/list.h
signal.$(OBJEXT): $(CCAN_DIR)/str/str.h
signal.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-signal.$(OBJEXT): $(hdrdir)/ruby/version.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
@@ -16468,7 +14345,6 @@ 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/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
@@ -16537,6 +14413,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
@@ -16567,6 +14444,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
@@ -16587,7 +14465,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
@@ -16598,7 +14475,6 @@ signal.$(OBJEXT): {$(VPATH)}vm_core.h
signal.$(OBJEXT): {$(VPATH)}vm_debug.h
signal.$(OBJEXT): {$(VPATH)}vm_opts.h
sprintf.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-sprintf.$(OBJEXT): $(hdrdir)/ruby/version.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/bignum.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/bits.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -16673,7 +14549,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
@@ -16743,6 +14618,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
@@ -16773,6 +14649,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
@@ -16854,7 +14731,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
@@ -16914,6 +14790,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
@@ -16944,6 +14821,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
@@ -16956,7 +14834,6 @@ 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
@@ -17020,7 +14897,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
@@ -17089,6 +14965,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
@@ -17119,6 +14996,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
@@ -17138,12 +15016,7 @@ 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): $(hdrdir)/ruby/version.h
string.$(OBJEXT): $(top_srcdir)/internal/array.h
string.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
string.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -17155,7 +15028,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
@@ -17185,6 +15057,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
@@ -17227,7 +15100,6 @@ 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/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
@@ -17297,6 +15169,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
@@ -17327,6 +15200,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
@@ -17338,9 +15212,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
@@ -17348,18 +15220,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
@@ -17396,7 +15263,6 @@ struct.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
struct.$(OBJEXT): $(CCAN_DIR)/list/list.h
struct.$(OBJEXT): $(CCAN_DIR)/str/str.h
struct.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-struct.$(OBJEXT): $(hdrdir)/ruby/version.h
struct.$(OBJEXT): $(top_srcdir)/internal/array.h
struct.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
struct.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -17429,7 +15295,6 @@ struct.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
struct.$(OBJEXT): {$(VPATH)}builtin.h
struct.$(OBJEXT): {$(VPATH)}config.h
struct.$(OBJEXT): {$(VPATH)}constant.h
-struct.$(OBJEXT): {$(VPATH)}debug_counter.h
struct.$(OBJEXT): {$(VPATH)}defines.h
struct.$(OBJEXT): {$(VPATH)}encoding.h
struct.$(OBJEXT): {$(VPATH)}id.h
@@ -17474,7 +15339,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
@@ -17543,6 +15407,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
@@ -17573,6 +15438,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
@@ -17591,31 +15457,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_debug.h
struct.$(OBJEXT): {$(VPATH)}vm_opts.h
-struct.$(OBJEXT): {$(VPATH)}vm_sync.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): $(hdrdir)/ruby/version.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
@@ -17625,7 +15481,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
@@ -17641,6 +15496,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
@@ -17685,7 +15541,6 @@ 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/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
@@ -17754,6 +15609,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
@@ -17784,6 +15640,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
@@ -17795,16 +15652,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
@@ -17812,11 +15665,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
@@ -17824,7 +15673,6 @@ thread.$(OBJEXT): $(CCAN_DIR)/list/list.h
thread.$(OBJEXT): $(CCAN_DIR)/str/str.h
thread.$(OBJEXT): $(hdrdir)/ruby.h
thread.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-thread.$(OBJEXT): $(hdrdir)/ruby/version.h
thread.$(OBJEXT): $(top_srcdir)/internal/array.h
thread.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
thread.$(OBJEXT): $(top_srcdir)/internal/bits.h
@@ -17847,28 +15695,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): $(top_srcdir)/prism/defines.h
-thread.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-thread.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-thread.$(OBJEXT): $(top_srcdir)/prism/node.h
-thread.$(OBJEXT): $(top_srcdir)/prism/options.h
-thread.$(OBJEXT): $(top_srcdir)/prism/pack.h
-thread.$(OBJEXT): $(top_srcdir)/prism/parser.h
-thread.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-thread.$(OBJEXT): $(top_srcdir)/prism/prism.h
-thread.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-thread.$(OBJEXT): {$(VPATH)}$(COROUTINE_H)
thread.$(OBJEXT): {$(VPATH)}assert.h
thread.$(OBJEXT): {$(VPATH)}atomic.h
thread.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -17889,6 +15715,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
@@ -17932,7 +15759,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
@@ -18001,6 +15827,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
@@ -18031,6 +15858,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
@@ -18046,18 +15874,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)}prism/ast.h
-thread.$(OBJEXT): {$(VPATH)}prism/version.h
-thread.$(OBJEXT): {$(VPATH)}prism_compile.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
@@ -18066,7 +15890,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
@@ -18074,10 +15897,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
@@ -18088,7 +15907,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
@@ -18099,7 +15917,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
@@ -18156,7 +15973,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
@@ -18225,6 +16041,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
@@ -18255,6 +16072,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
@@ -18266,24 +16084,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
@@ -18353,7 +16163,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
@@ -18422,6 +16231,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
@@ -18452,6 +16262,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
@@ -18471,6 +16282,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
@@ -18530,7 +16519,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
@@ -18590,6 +16578,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
@@ -18620,6 +16609,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
@@ -18642,7 +16632,6 @@ variable.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
variable.$(OBJEXT): $(CCAN_DIR)/list/list.h
variable.$(OBJEXT): $(CCAN_DIR)/str/str.h
variable.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-variable.$(OBJEXT): $(hdrdir)/ruby/version.h
variable.$(OBJEXT): $(top_srcdir)/internal/array.h
variable.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
variable.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -18720,7 +16709,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
@@ -18789,6 +16777,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
@@ -18819,6 +16808,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
@@ -18839,13 +16829,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
@@ -18887,7 +16876,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
@@ -18930,7 +16918,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
@@ -18963,15 +16950,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
@@ -18999,6 +16977,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
@@ -19029,6 +17008,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
@@ -19042,14 +17022,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
@@ -19065,7 +17042,6 @@ vm.$(OBJEXT): $(CCAN_DIR)/list/list.h
vm.$(OBJEXT): $(CCAN_DIR)/str/str.h
vm.$(OBJEXT): $(hdrdir)/ruby.h
vm.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-vm.$(OBJEXT): $(hdrdir)/ruby/version.h
vm.$(OBJEXT): $(top_srcdir)/internal/array.h
vm.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
vm.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -19075,7 +17051,6 @@ vm.$(OBJEXT): $(top_srcdir)/internal/compar.h
vm.$(OBJEXT): $(top_srcdir)/internal/compile.h
vm.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm.$(OBJEXT): $(top_srcdir)/internal/cont.h
-vm.$(OBJEXT): $(top_srcdir)/internal/encoding.h
vm.$(OBJEXT): $(top_srcdir)/internal/error.h
vm.$(OBJEXT): $(top_srcdir)/internal/eval.h
vm.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
@@ -19089,7 +17064,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
@@ -19097,31 +17071,9 @@ vm.$(OBJEXT): $(top_srcdir)/internal/string.h
vm.$(OBJEXT): $(top_srcdir)/internal/struct.h
vm.$(OBJEXT): $(top_srcdir)/internal/symbol.h
vm.$(OBJEXT): $(top_srcdir)/internal/thread.h
-vm.$(OBJEXT): $(top_srcdir)/internal/transcode.h
vm.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-vm.$(OBJEXT): $(top_srcdir)/prism/defines.h
-vm.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-vm.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-vm.$(OBJEXT): $(top_srcdir)/prism/node.h
-vm.$(OBJEXT): $(top_srcdir)/prism/options.h
-vm.$(OBJEXT): $(top_srcdir)/prism/pack.h
-vm.$(OBJEXT): $(top_srcdir)/prism/parser.h
-vm.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-vm.$(OBJEXT): $(top_srcdir)/prism/prism.h
-vm.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
vm.$(OBJEXT): {$(VPATH)}assert.h
vm.$(OBJEXT): {$(VPATH)}atomic.h
vm.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -19141,6 +17093,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
@@ -19186,7 +17139,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
@@ -19255,6 +17207,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
@@ -19285,6 +17238,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
@@ -19299,21 +17253,17 @@ 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
-vm.$(OBJEXT): {$(VPATH)}prism/ast.h
-vm.$(OBJEXT): {$(VPATH)}prism/version.h
-vm.$(OBJEXT): {$(VPATH)}prism_compile.h
vm.$(OBJEXT): {$(VPATH)}probes.dmyh
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
@@ -19343,10 +17293,8 @@ vm_backtrace.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
vm_backtrace.$(OBJEXT): $(CCAN_DIR)/list/list.h
vm_backtrace.$(OBJEXT): $(CCAN_DIR)/str/str.h
vm_backtrace.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-vm_backtrace.$(OBJEXT): $(hdrdir)/ruby/version.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
@@ -19357,27 +17305,6 @@ vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/string.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/defines.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/node.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/options.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/pack.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/parser.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/prism.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
vm_backtrace.$(OBJEXT): {$(VPATH)}assert.h
vm_backtrace.$(OBJEXT): {$(VPATH)}atomic.h
vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -19392,7 +17319,6 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
vm_backtrace.$(OBJEXT): {$(VPATH)}config.h
vm_backtrace.$(OBJEXT): {$(VPATH)}constant.h
vm_backtrace.$(OBJEXT): {$(VPATH)}debug.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}debug_counter.h
vm_backtrace.$(OBJEXT): {$(VPATH)}defines.h
vm_backtrace.$(OBJEXT): {$(VPATH)}encoding.h
vm_backtrace.$(OBJEXT): {$(VPATH)}eval_intern.h
@@ -19438,7 +17364,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
@@ -19507,6 +17432,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
@@ -19537,6 +17463,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
@@ -19554,12 +17481,8 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}missing.h
vm_backtrace.$(OBJEXT): {$(VPATH)}node.h
vm_backtrace.$(OBJEXT): {$(VPATH)}onigmo.h
vm_backtrace.$(OBJEXT): {$(VPATH)}oniguruma.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}prism/ast.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}prism/version.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}prism_compile.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
@@ -19567,9 +17490,7 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
vm_backtrace.$(OBJEXT): {$(VPATH)}thread_native.h
vm_backtrace.$(OBJEXT): {$(VPATH)}vm_backtrace.c
vm_backtrace.$(OBJEXT): {$(VPATH)}vm_core.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}vm_debug.h
vm_backtrace.$(OBJEXT): {$(VPATH)}vm_opts.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}vm_sync.h
vm_dump.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
vm_dump.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
vm_dump.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -19585,27 +17506,6 @@ vm_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/defines.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/node.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/options.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/pack.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/parser.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/prism.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
vm_dump.$(OBJEXT): {$(VPATH)}addr2line.h
vm_dump.$(OBJEXT): {$(VPATH)}assert.h
vm_dump.$(OBJEXT): {$(VPATH)}atomic.h
@@ -19621,7 +17521,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
@@ -19664,7 +17564,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
@@ -19697,15 +17596,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
@@ -19733,6 +17623,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
@@ -19763,6 +17654,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
@@ -19778,17 +17670,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)}prism/ast.h
-vm_dump.$(OBJEXT): {$(VPATH)}prism/version.h
-vm_dump.$(OBJEXT): {$(VPATH)}prism_compile.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
@@ -19810,7 +17696,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
@@ -19829,7 +17714,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
@@ -19872,7 +17757,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
@@ -19905,15 +17789,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
@@ -19941,6 +17816,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
@@ -19971,6 +17847,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
@@ -19985,13 +17862,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
@@ -20010,8 +17884,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/bits.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
@@ -20019,31 +17891,9 @@ vm_trace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-vm_trace.$(OBJEXT): $(top_srcdir)/internal/thread.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/defines.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/node.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/options.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/pack.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/parser.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/prism.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
vm_trace.$(OBJEXT): {$(VPATH)}assert.h
vm_trace.$(OBJEXT): {$(VPATH)}atomic.h
vm_trace.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -20105,7 +17955,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
@@ -20174,6 +18023,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
@@ -20204,6 +18054,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
@@ -20218,17 +18069,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)}prism/ast.h
-vm_trace.$(OBJEXT): {$(VPATH)}prism/version.h
-vm_trace.$(OBJEXT): {$(VPATH)}prism_compile.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
@@ -20236,208 +18083,9 @@ vm_trace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
vm_trace.$(OBJEXT): {$(VPATH)}thread_native.h
vm_trace.$(OBJEXT): {$(VPATH)}trace_point.rbinc
vm_trace.$(OBJEXT): {$(VPATH)}vm_core.h
-vm_trace.$(OBJEXT): {$(VPATH)}vm_debug.h
vm_trace.$(OBJEXT): {$(VPATH)}vm_opts.h
-vm_trace.$(OBJEXT): {$(VPATH)}vm_sync.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
@@ -20445,8 +18093,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
@@ -20455,7 +18101,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
@@ -20463,27 +18108,6 @@ yjit.$(OBJEXT): $(top_srcdir)/internal/string.h
yjit.$(OBJEXT): $(top_srcdir)/internal/variable.h
yjit.$(OBJEXT): $(top_srcdir)/internal/vm.h
yjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/defines.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/diagnostic.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/node.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/options.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/pack.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/parser.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/prism.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_state_stack.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string_list.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
yjit.$(OBJEXT): {$(VPATH)}assert.h
yjit.$(OBJEXT): {$(VPATH)}atomic.h
yjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -20502,6 +18126,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
@@ -20547,7 +18172,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
@@ -20616,6 +18240,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
@@ -20646,7 +18271,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
@@ -20664,15 +18289,11 @@ yjit.$(OBJEXT): {$(VPATH)}missing.h
yjit.$(OBJEXT): {$(VPATH)}node.h
yjit.$(OBJEXT): {$(VPATH)}onigmo.h
yjit.$(OBJEXT): {$(VPATH)}oniguruma.h
-yjit.$(OBJEXT): {$(VPATH)}prism/ast.h
-yjit.$(OBJEXT): {$(VPATH)}prism/version.h
-yjit.$(OBJEXT): {$(VPATH)}prism_compile.h
yjit.$(OBJEXT): {$(VPATH)}probes.dmyh
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 081b4e2dea..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)) {
@@ -263,28 +257,25 @@ cmp_clamp(int argc, VALUE *argv, VALUE x)
* <code>==</code>, <code>>=</code>, and <code>></code>) and the
* method <code>between?</code>.
*
- * class StringSorter
+ * class SizeMatters
* include Comparable
- *
* attr :str
* def <=>(other)
* str.size <=> other.str.size
* end
- *
* def initialize(str)
* @str = str
* end
- *
* def inspect
* @str
* end
* end
*
- * s1 = StringSorter.new("Z")
- * s2 = StringSorter.new("YY")
- * s3 = StringSorter.new("XXX")
- * s4 = StringSorter.new("WWWW")
- * s5 = StringSorter.new("VVVVV")
+ * s1 = SizeMatters.new("Z")
+ * s2 = SizeMatters.new("YY")
+ * s3 = SizeMatters.new("XXX")
+ * s4 = SizeMatters.new("WWWW")
+ * s5 = SizeMatters.new("VVVVV")
*
* s1 < s2 #=> true
* s4.between?(s1, s3) #=> false
@@ -298,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 110530f89f..c20ef48c43 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,7 +39,6 @@
#include "vm_core.h"
#include "vm_callinfo.h"
#include "vm_debug.h"
-#include "yjit.h"
#include "builtin.h"
#include "insns.inc"
@@ -119,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;
};
@@ -333,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)])
@@ -487,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);
@@ -721,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)
{
@@ -864,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:
@@ -880,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;
@@ -893,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;
}
}
@@ -967,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)
{
@@ -997,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;
}
@@ -1373,32 +1243,6 @@ new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
return adjust;
}
-static void
-iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE, VALUE), VALUE data)
-{
- const char *types = insn_op_types(insn->insn_id);
- for (int j = 0; types[j]; j++) {
- char type = types[j];
- switch (type) {
- case TS_CDHASH:
- case TS_ISEQ:
- case TS_VALUE:
- case TS_IC: // constant path array
- case TS_CALLDATA: // ci is stored.
- func(OPERAND_AT(insn, j), data);
- break;
- default:
- break;
- }
- }
-}
-
-static void
-iseq_insn_each_object_write_barrier(VALUE obj, VALUE iseq)
-{
- RB_OBJ_WRITTEN(iseq, Qundef, obj);
-}
-
static INSN *
new_insn_core(rb_iseq_t *iseq, const NODE *line_node,
int insn_id, int argc, VALUE *argv)
@@ -1416,9 +1260,6 @@ new_insn_core(rb_iseq_t *iseq, const NODE *line_node,
iobj->operands = argv;
iobj->operand_size = argc;
iobj->sc_state = 0;
-
- iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
-
return iobj;
}
@@ -1485,8 +1326,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");
@@ -1515,14 +1355,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));
}
}
@@ -1534,7 +1371,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;
@@ -1547,7 +1384,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);
@@ -1562,8 +1399,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;
}
}
@@ -1575,9 +1411,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;
@@ -1624,6 +1460,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)
@@ -1653,12 +1496,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;
}
@@ -1899,7 +1740,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);
@@ -1918,7 +1759,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) {
@@ -1927,7 +1768,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;
@@ -1939,7 +1780,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;
}
@@ -1952,7 +1793,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;
}
@@ -1983,7 +1824,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;
@@ -2004,14 +1845,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));
@@ -2026,7 +1867,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;
}
@@ -2512,12 +2353,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;
@@ -2656,8 +2492,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;
@@ -2795,18 +2631,16 @@ iseq_set_exception_table(rb_iseq_t *iseq)
struct iseq_catch_table_entry *entry;
ISEQ_BODY(iseq)->catch_table = NULL;
-
- 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(catch_table_ary);
+ 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_TRANSIENT(ISEQ_COMPILE_DATA(iseq)->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));
@@ -2835,8 +2669,6 @@ 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;
}
@@ -2975,6 +2807,7 @@ 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]++;
}
}
@@ -2991,7 +2824,8 @@ remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
/* do nothing */
}
else if (IS_ADJUST(i)) {
- return 0;
+ LABEL *dest = ((ADJUST *)i)->label;
+ if (dest && dest->unremovable) return 0;
}
end = i;
} while ((i = i->next) != 0);
@@ -3485,7 +3319,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 */
@@ -3812,10 +3646,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;
- }
}
}
}
@@ -3833,166 +3663,6 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
}
- if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == Qtrue) {
- LINK_ELEMENT *niobj = &iobj->link;
-
- /*
- * Eliminate array allocation for f(1, *a)
- *
- * splatarray true
- * send ARGS_SPLAT and not KW_SPLAT|ARGS_BLOCKARG
- * =>
- * splatarray false
- * send
- */
- if (IS_NEXT_INSN_ID(niobj, send)) {
- niobj = niobj->next;
- unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
- if ((flag & VM_CALL_ARGS_SPLAT) && !(flag & (VM_CALL_KW_SPLAT|VM_CALL_ARGS_BLOCKARG))) {
- OPERAND_AT(iobj, 0) = Qfalse;
- }
- } else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable)) {
- niobj = niobj->next;
-
- if (IS_NEXT_INSN_ID(niobj, send)) {
- niobj = niobj->next;
- unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
-
- if ((flag & VM_CALL_ARGS_SPLAT)) {
- /*
- * Eliminate array allocation for f(1, *a, &lvar) and f(1, *a, &@iv)
- *
- * splatarray true
- * getlocal / getinstancevariable
- * send ARGS_SPLAT|ARGS_BLOCKARG and not KW_SPLAT
- * =>
- * splatarray false
- * getlocal / getinstancevariable
- * send
- */
- if ((flag & VM_CALL_ARGS_BLOCKARG) && !(flag & VM_CALL_KW_SPLAT)) {
- OPERAND_AT(iobj, 0) = Qfalse;
- }
-
- /*
- * Eliminate array allocation for f(*a, **lvar) and f(*a, **@iv)
- *
- * splatarray true
- * getlocal / getinstancevariable
- * send ARGS_SPLAT|KW_SPLAT and not ARGS_BLOCKARG
- * =>
- * splatarray false
- * getlocal / getinstancevariable
- * send
- */
- else if (!(flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT)) {
- OPERAND_AT(iobj, 0) = Qfalse;
- }
- }
- }
- else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
- IS_NEXT_INSN_ID(niobj, getblockparamproxy)) {
- niobj = niobj->next;
-
- /*
- * Eliminate array allocation for f(*a, **lvar, &lvar) and f(*a, **@iv, &@iv)
- *
- * splatarray true
- * getlocal / getinstancevariable
- * getlocal / getinstancevariable / getblockparamproxy
- * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
- * =>
- * splatarray false
- * getlocal / getinstancevariable
- * getlocal / getinstancevariable / getblockparamproxy
- * send
- */
- if (IS_NEXT_INSN_ID(niobj, send)) {
- niobj = niobj->next;
- unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
-
- if ((flag & VM_CALL_ARGS_SPLAT) && (flag & VM_CALL_KW_SPLAT) && (flag & VM_CALL_ARGS_BLOCKARG)) {
- OPERAND_AT(iobj, 0) = Qfalse;
- }
- }
- }
- }
- else if (IS_NEXT_INSN_ID(niobj, getblockparamproxy)) {
- niobj = niobj->next;
-
- if (IS_NEXT_INSN_ID(niobj, send)) {
- niobj = niobj->next;
- unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
-
- /*
- * Eliminate array allocation for f(1, *a, &arg)
- *
- * splatarray true
- * getblockparamproxy
- * send ARGS_SPLAT|ARGS_BLOCKARG and not KW_SPLAT
- * =>
- * splatarray false
- * getblockparamproxy
- * send
- */
- if ((flag & VM_CALL_ARGS_BLOCKARG) & (flag & VM_CALL_ARGS_SPLAT) && !(flag & VM_CALL_KW_SPLAT)) {
- OPERAND_AT(iobj, 0) = Qfalse;
- }
- }
- }
- else if (IS_NEXT_INSN_ID(niobj, duphash)) {
- niobj = niobj->next;
-
- /*
- * Eliminate array allocation for f(*a, kw: 1)
- *
- * splatarray true
- * duphash
- * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
- * =>
- * splatarray false
- * duphash
- * send
- */
- if (IS_NEXT_INSN_ID(niobj, send)) {
- niobj = niobj->next;
- unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
-
- if ((flag & VM_CALL_ARGS_SPLAT) && (flag & VM_CALL_KW_SPLAT) &&
- (flag & VM_CALL_KW_SPLAT_MUT) && !(flag & VM_CALL_ARGS_BLOCKARG)) {
- OPERAND_AT(iobj, 0) = Qfalse;
- }
- }
- else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
- IS_NEXT_INSN_ID(niobj, getblockparamproxy)) {
- niobj = niobj->next;
-
- /*
- * Eliminate array allocation for f(*a, kw: 1, &lvar) and f(*a, kw: 1, &@iv)
- *
- * splatarray true
- * duphash
- * getlocal / getinstancevariable / getblockparamproxy
- * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
- * =>
- * splatarray false
- * duphash
- * getlocal / getinstancevariable / getblockparamproxy
- * send
- */
- if (IS_NEXT_INSN_ID(niobj, send)) {
- niobj = niobj->next;
- unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
-
- if ((flag & VM_CALL_ARGS_SPLAT) && (flag & VM_CALL_KW_SPLAT) &&
- (flag & VM_CALL_KW_SPLAT_MUT) && (flag & VM_CALL_ARGS_BLOCKARG)) {
- OPERAND_AT(iobj, 0) = Qfalse;
- }
- }
- }
- }
- }
-
return COMPILE_OK;
}
@@ -4028,18 +3698,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;
}
}
}
@@ -4133,7 +3798,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;
}
@@ -4271,6 +3936,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)
{
@@ -4279,16 +4105,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;
}
@@ -4297,8 +4123,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;
@@ -4319,7 +4145,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;
@@ -4328,7 +4154,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);
@@ -4343,12 +4169,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;
}
@@ -4357,8 +4183,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);
}
@@ -4370,28 +4196,11 @@ compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
}
static int
-compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
{
int cnt;
-
- if (!RNODE_DREGX(node)->nd_next) {
- VALUE match = RNODE_DREGX(node)->nd_lit;
- if (RB_TYPE_P(match, T_REGEXP)) {
- if (!popped) {
- ADD_INSN1(ret, node, putobject, match);
- RB_OBJ_WRITTEN(iseq, Qundef, match);
- }
- return COMPILE_OK;
- }
- }
-
CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
- ADD_INSN2(ret, node, toregexp, INT2FIX(RNODE_DREGX(node)->nd_cflag), INT2FIX(cnt));
-
- if (popped) {
- ADD_INSN(ret, node, pop);
- }
-
+ ADD_INSN2(ret, node, toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
return COMPILE_OK;
}
@@ -4409,7 +4218,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);
@@ -4419,7 +4228,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);
@@ -4429,62 +4238,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:
@@ -4515,28 +4299,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;
}
@@ -4550,35 +4313,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.
@@ -4588,27 +4349,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);
@@ -4619,21 +4379,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));
}
}
@@ -4670,15 +4435,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;
}
}
@@ -4697,8 +4462,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;
}
@@ -4757,10 +4522,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) {
@@ -4768,8 +4533,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 */
@@ -4787,15 +4552,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;
@@ -4824,12 +4589,7 @@ compile_array_1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node)
}
else {
CHECK(COMPILE_(ret, "array element", node, FALSE));
- if (keyword_node_p(node)) {
- ADD_INSN1(ret, node, newarraykwsplat, INT2FIX(1));
- }
- else {
- ADD_INSN1(ret, node, newarray, INT2FIX(1));
- }
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
}
return 1;
@@ -4838,7 +4598,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
@@ -4846,7 +4606,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) {
@@ -4858,8 +4618,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;
}
@@ -4912,8 +4672,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) {
@@ -4921,14 +4681,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);
@@ -4951,16 +4711,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 */
@@ -4970,10 +4730,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) {
@@ -5036,7 +4796,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) {
@@ -5057,7 +4817,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;
}
@@ -5067,7 +4827,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)) {
@@ -5078,8 +4838,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);
}
@@ -5087,11 +4847,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;
}
@@ -5109,19 +4869,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;
@@ -5280,17 +5040,12 @@ 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(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;
+ ELEM_REMOVE(LAST_ELEMENT(pre));
+ ELEM_REMOVE((LINK_ELEMENT *)iobj);
+ pre->last = iobj->link.prev;
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
int argc = vm_ci_argc(ci) + 1;
@@ -5309,9 +5064,7 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
return COMPILE_NG;
}
- iobj->link.prev = lhs->last;
- lhs->last->next = &iobj->link;
- for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
+ ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
int argc = vm_ci_argc(ci);
ci = ci_argc_set(iseq, ci, argc - 1);
@@ -5320,11 +5073,9 @@ 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);
}
- if (!safenav_call) {
+ ADD_INSN(lhs, line_node, pop);
+ if (argc != 1) {
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);
@@ -5350,7 +5101,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;
@@ -5388,8 +5139,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;
}
@@ -5419,29 +5170,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++;
}
@@ -5458,31 +5211,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);
@@ -5492,9 +5246,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 {
@@ -5503,6 +5257,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));
}
@@ -5510,14 +5265,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;
@@ -5566,15 +5323,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;
@@ -5588,22 +5345,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));
@@ -5620,9 +5377,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 {
@@ -5636,9 +5393,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;
}
@@ -5680,13 +5437,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:
@@ -5706,48 +5463,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 */
@@ -5760,7 +5518,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);
}
@@ -5768,31 +5526,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);
@@ -5800,7 +5558,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;
}
@@ -5815,7 +5573,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;
@@ -5891,7 +5649,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);
}
@@ -5901,7 +5659,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);
@@ -5942,7 +5700,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 */
@@ -6018,137 +5776,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;
- 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
@@ -6160,7 +5860,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;
@@ -6174,11 +5874,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;
}
@@ -6214,19 +5914,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);
@@ -6247,9 +5947,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;
@@ -6263,7 +5963,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:
@@ -6274,21 +5974,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) {
@@ -6297,11 +6029,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,
@@ -6321,11 +6048,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,
@@ -6368,11 +6090,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);
@@ -6392,14 +6114,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:
@@ -6420,7 +6142,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;
}
@@ -6465,7 +6187,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;
@@ -6483,14 +6205,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);
}
@@ -6498,12 +6220,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:
@@ -6517,7 +6239,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(
@@ -6609,13 +6331,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;
@@ -6639,10 +6362,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) */));
}
@@ -6652,12 +6375,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));
@@ -6667,7 +6390,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) {
@@ -6681,7 +6404,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);
@@ -6690,8 +6413,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);
@@ -6769,8 +6492,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);
@@ -6823,25 +6547,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);
@@ -6955,12 +6679,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;
}
}
@@ -6987,28 +6711,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);
@@ -7037,9 +6761,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);
}
@@ -7053,8 +6777,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) {
@@ -7064,7 +6788,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));
}
}
@@ -7108,7 +6832,6 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
case NODE_COLON2:
case NODE_COLON3:
case NODE_BEGIN:
- case NODE_BLOCK:
CHECK(COMPILE(ret, "case in literal", node)); // (1)
if (in_single_pattern) {
ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
@@ -7122,7 +6845,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) {
@@ -7140,7 +6863,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);
@@ -7166,8 +6889,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);
@@ -7204,15 +6927,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);
@@ -7226,13 +6949,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:
@@ -7255,9 +6978,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));
}
@@ -7460,12 +7183,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);
@@ -7479,7 +7202,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 */
@@ -7495,14 +7218,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);
@@ -7517,7 +7240,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;
}
@@ -7559,7 +7282,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"));
@@ -7643,7 +7365,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 {
@@ -7662,27 +7384,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;
@@ -7724,18 +7446,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));
}
{
@@ -7779,7 +7501,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));
@@ -7814,7 +7536,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);
@@ -7849,7 +7571,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);
@@ -7872,7 +7594,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);
@@ -7886,10 +7608,11 @@ 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);
@@ -7920,7 +7643,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) {
@@ -8032,7 +7755,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);
@@ -8044,14 +7767,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);
@@ -8079,16 +7802,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:
@@ -8111,24 +7834,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;
}
@@ -8139,7 +7851,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);
@@ -8152,17 +7864,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);
@@ -8191,7 +7903,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) {
@@ -8300,13 +8012,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));
}
@@ -8323,14 +8035,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);
@@ -8373,12 +8085,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;
@@ -8459,60 +8171,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));
@@ -8536,8 +8204,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");
@@ -8551,9 +8219,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;
@@ -8574,25 +8241,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;
}
@@ -8601,15 +8267,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);
@@ -8628,7 +8294,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);
@@ -8704,7 +8372,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;
@@ -8783,7 +8451,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);
}
@@ -8793,16 +8461,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) {
@@ -8816,7 +8484,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 {
@@ -8837,9 +8505,6 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
flag |= VM_CALL_FCALL;
}
- if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
- ADD_INSN(ret, line_node, splatkw);
- }
ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
@@ -8856,10 +8521,8 @@ 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;
- int keyword_len = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
/*
* a[x] (op)= y
@@ -8887,9 +8550,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;
@@ -8897,28 +8560,12 @@ 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, &keywords);
- if (flag & VM_CALL_KW_SPLAT) {
- if (boff) {
- ADD_INSN(ret, node, splatkw);
- }
- else {
- /* Make sure to_hash is only called once and not twice */
- ADD_INSN(ret, node, dup);
- ADD_INSN(ret, node, splatkw);
- ADD_INSN(ret, node, pop);
- }
- }
+ argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
CHECK(!NIL_P(argc));
}
- int dup_argn = FIX2INT(argc) + 1 + boff;
- if (keywords) {
- keyword_len = keywords->keyword_len;
- dup_argn += keyword_len;
- }
- ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
+ ADD_INSN1(ret, node, dupn, FIXNUM_INC(argc, 1 + boff));
flag |= asgnflag;
- ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_KW_SPLAT_MUT), keywords);
+ ADD_SEND_WITH_FLAG(ret, node, idAREF, argc, INT2FIX(flag));
if (id == idOROP || id == idANDOP) {
/* a[x] ||= y or a[x] &&= y
@@ -8941,116 +8588,64 @@ 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, INT2FIX(dup_argn+1));
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
}
if (flag & VM_CALL_ARGS_SPLAT) {
- if (flag & VM_CALL_KW_SPLAT) {
- ADD_INSN1(ret, node, topn, INT2FIX(2 + boff));
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ if (boff > 0) {
+ ADD_INSN1(ret, node, dupn, INT2FIX(3));
ADD_INSN(ret, node, swap);
- ADD_INSN1(ret, node, newarray, INT2FIX(1));
- ADD_INSN(ret, node, concatarray);
- ADD_INSN1(ret, node, setn, INT2FIX(2 + boff));
ADD_INSN(ret, node, pop);
}
- else {
- ADD_INSN1(ret, node, newarray, INT2FIX(1));
- if (boff > 0) {
- ADD_INSN1(ret, node, dupn, INT2FIX(3));
- ADD_INSN(ret, node, swap);
- ADD_INSN(ret, node, pop);
- }
- ADD_INSN(ret, node, concatarray);
- if (boff > 0) {
- ADD_INSN1(ret, node, setn, INT2FIX(3));
- ADD_INSN(ret, node, pop);
- ADD_INSN(ret, node, pop);
- }
- }
- ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), keywords);
- }
- else if (flag & VM_CALL_KW_SPLAT) {
+ ADD_INSN(ret, node, concatarray);
if (boff > 0) {
- ADD_INSN1(ret, node, topn, INT2FIX(2));
- ADD_INSN(ret, node, swap);
ADD_INSN1(ret, node, setn, INT2FIX(3));
ADD_INSN(ret, node, pop);
+ ADD_INSN(ret, node, pop);
}
- ADD_INSN(ret, node, swap);
- ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
- }
- else if (keyword_len) {
- ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+1));
- ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+0));
- ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
+ ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
}
else {
if (boff > 0)
ADD_INSN(ret, node, swap);
- ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
+ ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
}
ADD_INSN(ret, node, pop);
ADD_INSNL(ret, node, jump, lfin);
ADD_LABEL(ret, label);
if (!popped) {
- ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
}
- ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
+ ADD_INSN1(ret, node, adjuststack, FIXNUM_INC(argc, 2+boff));
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, INT2FIX(dup_argn+1));
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
}
if (flag & VM_CALL_ARGS_SPLAT) {
- if (flag & VM_CALL_KW_SPLAT) {
- ADD_INSN1(ret, node, topn, INT2FIX(2 + boff));
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ if (boff > 0) {
+ ADD_INSN1(ret, node, dupn, INT2FIX(3));
ADD_INSN(ret, node, swap);
- ADD_INSN1(ret, node, newarray, INT2FIX(1));
- ADD_INSN(ret, node, concatarray);
- ADD_INSN1(ret, node, setn, INT2FIX(2 + boff));
ADD_INSN(ret, node, pop);
}
- else {
- ADD_INSN1(ret, node, newarray, INT2FIX(1));
- if (boff > 0) {
- ADD_INSN1(ret, node, dupn, INT2FIX(3));
- ADD_INSN(ret, node, swap);
- ADD_INSN(ret, node, pop);
- }
- ADD_INSN(ret, node, concatarray);
- if (boff > 0) {
- ADD_INSN1(ret, node, setn, INT2FIX(3));
- ADD_INSN(ret, node, pop);
- ADD_INSN(ret, node, pop);
- }
- }
- ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), keywords);
- }
- else if (flag & VM_CALL_KW_SPLAT) {
+ ADD_INSN(ret, node, concatarray);
if (boff > 0) {
- ADD_INSN1(ret, node, topn, INT2FIX(2));
- ADD_INSN(ret, node, swap);
ADD_INSN1(ret, node, setn, INT2FIX(3));
ADD_INSN(ret, node, pop);
+ ADD_INSN(ret, node, pop);
}
- ADD_INSN(ret, node, swap);
- ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
- }
- else if (keyword_len) {
- ADD_INSN(ret, node, dup);
- ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+2));
- ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+1));
- ADD_INSN(ret, node, pop);
- ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
+ ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
}
else {
if (boff > 0)
ADD_INSN(ret, node, swap);
- ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
+ ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
}
ADD_INSN(ret, node, pop);
}
@@ -9061,8 +8656,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);
@@ -9120,9 +8715,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);
@@ -9143,7 +8738,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));
@@ -9159,7 +8754,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);
@@ -9185,21 +8780,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),
@@ -9210,17 +8805,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 */
@@ -9234,9 +8829,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) {
@@ -9255,11 +8850,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);
@@ -9270,7 +8865,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);
@@ -9288,7 +8883,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;
}
@@ -9306,12 +8901,9 @@ 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);
- if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
- ADD_INSN(args, node, splatkw);
- }
}
else {
/* NODE_ZSUPER */
@@ -9382,11 +8974,14 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
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);
- assert(local_kwd->num > 0);
- ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
+ if (local_kwd->num > 0) {
+ ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
+ flag |= VM_CALL_KW_SPLAT_MUT;
+ }
}
else {
ADD_INSN1(args, node, newhash, INT2FIX(0));
+ flag |= VM_CALL_KW_SPLAT_MUT;
}
for (i = 0; i < local_kwd->num; ++i) {
ID id = local_kwd->table[i];
@@ -9395,12 +8990,24 @@ 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));
- 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);
+ --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++;
+
+ 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;
}
}
@@ -9438,8 +9045,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 {
@@ -9473,17 +9080,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;
}
@@ -9491,8 +9098,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) {
@@ -9504,7 +9111,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 &&
@@ -9534,8 +9141,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);
@@ -9546,19 +9153,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) {
@@ -9571,13 +9178,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);
@@ -9626,7 +9233,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 */
@@ -9650,7 +9257,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;
@@ -9662,26 +9269,24 @@ 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;
- struct rb_callinfo_kwarg *keywords = NULL;
/* optimization shortcut
* obj["literal"] = value -> opt_aset_with(obj, "literal", value)
*/
- if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
- 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 (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));
@@ -9695,10 +9300,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, &keywords);
+ 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;
@@ -9780,7 +9385,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)) {
@@ -9835,7 +9440,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:
@@ -9851,7 +9456,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);
}
@@ -9864,25 +9469,22 @@ 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);
@@ -9892,8 +9494,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) {
@@ -9911,27 +9513,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);
@@ -9939,11 +9541,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) {
@@ -9951,18 +9553,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:
@@ -10004,6 +9606,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;
@@ -10015,18 +9629,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);
@@ -10034,34 +9648,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) {
@@ -10072,26 +9686,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;
}
@@ -10101,22 +9715,17 @@ 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) {
- if (UNLIKELY(RNODE_LIT(node)->nd_lit == rb_mRubyVMFrozenCore)) {
- ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); // [Bug #20569]
- }
- else {
- ADD_INSN1(ret, node, putobject, RNODE_LIT(node)->nd_lit);
- }
- RB_OBJ_WRITTEN(iseq, Qundef, RNODE_LIT(node)->nd_lit);
+ 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);
@@ -10148,7 +9757,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));
@@ -10169,15 +9778,20 @@ 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, popped);
+ case NODE_DREGX:{
+ compile_dregx(iseq, ret, node);
+
+ if (popped) {
+ ADD_INSN(ret, node, pop);
+ }
break;
+ }
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);
@@ -10189,36 +9803,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) {
@@ -10227,8 +9841,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);
@@ -10243,13 +9857,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);
@@ -10261,8 +9875,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) {
@@ -10272,8 +9886,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) {
@@ -10284,7 +9898,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) {
@@ -10293,15 +9907,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) {
@@ -10310,14 +9924,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) {
@@ -10327,10 +9941,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,
@@ -10408,7 +10022,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);
@@ -10439,7 +10053,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));
@@ -10650,12 +10264,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)
{
@@ -10819,7 +10427,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);
@@ -10845,7 +10452,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;
}
@@ -11129,14 +10735,8 @@ iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
return keyword;
}
-static void
-iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
-{
- rb_gc_mark(obj);
-}
-
void
-rb_iseq_mark_and_pin_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);
@@ -11161,7 +10761,29 @@ rb_iseq_mark_and_pin_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_pin, (VALUE)0);
+ int j;
+ const char *types = insn_op_types(iobj->insn_id);
+
+ for (j = 0; types[j]; j++) {
+ char type = types[j];
+ switch (type) {
+ case TS_CDHASH:
+ case TS_ISEQ:
+ case TS_VALUE:
+ case TS_IC: // constant path array
+ case TS_CALLDATA: // ci is stored.
+ {
+ VALUE op = OPERAND_AT(iobj, j);
+
+ if (!SPECIAL_CONST_P(op)) {
+ rb_gc_mark(op);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
}
pos += (int)size;
}
@@ -11334,7 +10956,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
@@ -11345,27 +10967,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 {
@@ -11400,7 +11012,7 @@ struct ibf_load {
struct pinned_list {
long size;
- VALUE buffer[1];
+ VALUE * buffer;
};
static void
@@ -11415,14 +11027,25 @@ pinned_list_mark(void *ptr)
}
}
+static void
+pinned_list_free(void *ptr)
+{
+ struct pinned_list *list = (struct pinned_list *)ptr;
+ xfree(list->buffer);
+ xfree(ptr);
+}
+
+static size_t
+pinned_list_memsize(const void *ptr)
+{
+ struct pinned_list *list = (struct pinned_list *)ptr;
+ return sizeof(struct pinned_list) + (list->size * sizeof(VALUE *));
+}
+
static const rb_data_type_t pinned_list_type = {
"pinned_list",
- {
- pinned_list_mark,
- RUBY_DEFAULT_FREE,
- NULL, // No external memory to report,
- },
- 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ {pinned_list_mark, pinned_list_free, pinned_list_memsize,},
+ 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
@@ -11456,10 +11079,13 @@ pinned_list_store(VALUE list, long offset, VALUE object)
static VALUE
pinned_list_new(long size)
{
- size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
- VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
- struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
+ struct pinned_list * ptr;
+ VALUE obj_list =
+ TypedData_Make_Struct(0, struct pinned_list, &pinned_list_type, ptr);
+
+ ptr->buffer = xcalloc(size, sizeof(VALUE));
ptr->size = size;
+
return obj_list;
}
@@ -12252,34 +11878,13 @@ ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
return offset;
}
-struct outer_variable_pair {
- ID id;
- VALUE name;
- VALUE val;
-};
-
-struct outer_variable_list {
- size_t num;
- struct outer_variable_pair pairs[1];
-};
-
static enum rb_id_table_iterator_result
-store_outer_variable(ID id, VALUE val, void *dump)
+dump_outer_variable(ID id, VALUE val, void *dump)
{
- struct outer_variable_list *ovlist = dump;
- struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
- pair->id = id;
- pair->name = rb_id2str(id);
- pair->val = val;
- return ID_TABLE_CONTINUE;
-}
+ ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
+ ibf_dump_write_small_value(dump, val);
-static int
-outer_variable_cmp(const void *a, const void *b, void *arg)
-{
- const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
- const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
- return rb_str_cmp(ap->name, bp->name);
+ return ID_TABLE_CONTINUE;
}
static ibf_offset_t
@@ -12289,24 +11894,12 @@ ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
ibf_offset_t offset = ibf_dump_pos(dump);
- size_t size = ovs ? rb_id_table_size(ovs) : 0;
- ibf_dump_write_small_value(dump, (VALUE)size);
- if (size > 0) {
- VALUE buff;
- size_t buffsize =
- rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
- offsetof(struct outer_variable_list, pairs),
- rb_eArgError);
- struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
- ovlist->num = 0;
- rb_id_table_foreach(ovs, store_outer_variable, ovlist);
- ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
- for (size_t i = 0; i < size; ++i) {
- ID id = ovlist->pairs[i].id;
- ID val = ovlist->pairs[i].val;
- ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
- ibf_dump_write_small_value(dump, val);
- }
+ if (ovs) {
+ ibf_dump_write_small_value(dump, (VALUE)rb_id_table_size(ovs));
+ rb_id_table_foreach(ovs, dump_outer_variable, (void *)dump);
+ }
+ else {
+ ibf_dump_write_small_value(dump, (VALUE)0);
}
return offset;
@@ -12337,7 +11930,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);
@@ -12492,7 +12084,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
@@ -12604,7 +12197,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);
@@ -12676,19 +12270,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);
@@ -13128,12 +12717,8 @@ ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_head
const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
int sign = bignum->slen > 0;
ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
- const int big_unpack_flags = /* c.f. rb_big_unpack() */
- INTEGER_PACK_LSWORD_FIRST |
- INTEGER_PACK_NATIVE_BYTE_ORDER;
- VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
- big_unpack_flags |
- (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
+ VALUE obj = rb_integer_unpack(bignum->digits, len * 2, 2, 0,
+ INTEGER_PACK_LITTLE_ENDIAN | (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
if (header->internal) rb_obj_hide(obj);
if (header->frozen) rb_obj_freeze(obj);
return obj;
@@ -13225,7 +12810,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 */
@@ -13318,7 +12903,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 */
@@ -13461,13 +13046,14 @@ ibf_dump_free(void *ptr)
st_free_table(dump->iseq_table);
dump->iseq_table = 0;
}
+ ruby_xfree(dump);
}
static size_t
ibf_dump_memsize(const void *ptr)
{
struct ibf_dump *dump = (struct ibf_dump *)ptr;
- size_t size = 0;
+ size_t size = sizeof(*dump);
if (dump->iseq_table) size += st_memsize(dump->iseq_table);
if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
return size;
@@ -13476,7 +13062,7 @@ ibf_dump_memsize(const void *ptr)
static const rb_data_type_t ibf_dump_type = {
"ibf_dump",
{ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
};
static void
@@ -13512,6 +13098,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 */
@@ -13520,8 +13107,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);
@@ -13539,6 +13124,8 @@ rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
ibf_dump_overwrite(dump, &header, sizeof(header), 0);
str = dump->global_buffer.str;
+ ibf_dump_free(dump);
+ DATA_PTR(dump_obj) = NULL;
RB_GC_GUARD(dump_obj);
return str;
}
@@ -13569,7 +13156,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);
@@ -13612,12 +13199,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",
@@ -13631,39 +13222,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);
- }
- if (header->endian != IBF_ENDIAN_MARK) {
- rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
+ load->header->major_version, load->header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
}
- if (header->wordsize != SIZEOF_VALUE) {
- rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
+ if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
+ rb_raise(rb_eRuntimeError, "unmatched platform");
}
- 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",
@@ -13678,9 +13265,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);
@@ -13754,5 +13341,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 b6fbc856f1..57962f9013 100644
--- a/complex.c
+++ b/complex.c
@@ -24,7 +24,6 @@
#include "internal/numeric.h"
#include "internal/object.h"
#include "internal/rational.h"
-#include "internal/string.h"
#include "ruby_assert.h"
#define ZERO INT2FIX(0)
@@ -392,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);
@@ -475,19 +473,12 @@ nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
/*
* call-seq:
- * Complex.rect(real, imag = 0) -> complex
+ * Complex.rect(real[, imag]) -> complex
+ * Complex.rectangular(real[, imag]) -> complex
*
- * Returns a new \Complex object formed from the arguments,
- * each of which must be an instance of Numeric,
- * or an instance of one of its subclasses:
- * \Complex, Float, Integer, Rational;
- * see {Rectangular Coordinates}[rdoc-ref:Complex@Rectangular+Coordinates]:
+ * Returns a complex object which denotes the given rectangular form.
*
- * Complex.rect(3) # => (3+0i)
- * Complex.rect(3, Math::PI) # => (3+3.141592653589793i)
- * Complex.rect(-3, -Math::PI) # => (-3-3.141592653589793i)
- *
- * \Complex.rectangular is an alias for \Complex.rect.
+ * Complex.rectangular(1, 2) #=> (1+2i)
*/
static VALUE
nucomp_s_new(int argc, VALUE *argv, VALUE klass)
@@ -524,54 +515,39 @@ static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
/*
* call-seq:
- * Complex(real, imag = 0, exception: true) -> complex or nil
- * Complex(s, exception: true) -> complex or nil
- *
- * Returns a new \Complex object if the arguments are valid;
- * otherwise raises an exception if +exception+ is +true+;
- * otherwise returns +nil+.
- *
- * With Numeric arguments +real+ and +imag+,
- * returns <tt>Complex.rect(real, imag)</tt> if the arguments are valid.
- *
- * With string argument +s+, returns a new \Complex object if the argument is valid;
- * the string may have:
- *
- * - One or two numeric substrings,
- * each of which specifies a Complex, Float, Integer, Numeric, or Rational value,
- * specifying {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates]:
- *
- * - Sign-separated real and imaginary numeric substrings
- * (with trailing character <tt>'i'</tt>):
- *
- * Complex('1+2i') # => (1+2i)
- * Complex('+1+2i') # => (1+2i)
- * Complex('+1-2i') # => (1-2i)
- * Complex('-1+2i') # => (-1+2i)
- * Complex('-1-2i') # => (-1-2i)
- *
- * - Real-only numeric string (without trailing character <tt>'i'</tt>):
- *
- * Complex('1') # => (1+0i)
- * Complex('+1') # => (1+0i)
- * Complex('-1') # => (-1+0i)
- *
- * - Imaginary-only numeric string (with trailing character <tt>'i'</tt>):
- *
- * Complex('1i') # => (0+1i)
- * Complex('+1i') # => (0+1i)
- * Complex('-1i') # => (0-1i)
- *
- * - At-sign separated real and imaginary rational substrings,
- * each of which specifies a Rational value,
- * specifying {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
- *
- * Complex('1/2@3/4') # => (0.36584443443691045+0.34081938001166706i)
- * Complex('+1/2@+3/4') # => (0.36584443443691045+0.34081938001166706i)
- * Complex('+1/2@-3/4') # => (0.36584443443691045-0.34081938001166706i)
- * Complex('-1/2@+3/4') # => (-0.36584443443691045-0.34081938001166706i)
- * Complex('-1/2@-3/4') # => (-0.36584443443691045+0.34081938001166706i)
- *
+ * Complex(x[, y], exception: true) -> numeric or nil
+ *
+ * Returns x+i*y;
+ *
+ * Complex(1, 2) #=> (1+2i)
+ * Complex('1+2i') #=> (1+2i)
+ * Complex(nil) #=> TypeError
+ * Complex(1, nil) #=> TypeError
+ *
+ * Complex(1, nil, exception: false) #=> nil
+ * Complex('1+2', exception: false) #=> nil
+ *
+ * Syntax of string form:
+ *
+ * string form = extra spaces , complex , extra spaces ;
+ * complex = real part | [ sign ] , imaginary part
+ * | real part , sign , imaginary part
+ * | rational , "@" , rational ;
+ * real part = rational ;
+ * imaginary part = imaginary unit | unsigned rational , imaginary unit ;
+ * rational = [ sign ] , unsigned rational ;
+ * unsigned rational = numerator | numerator , "/" , denominator ;
+ * numerator = integer part | fractional part | integer part , fractional part ;
+ * denominator = digits ;
+ * integer part = digits ;
+ * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
+ * imaginary unit = "i" | "I" | "j" | "J" ;
+ * sign = "-" | "+" ;
+ * digits = digit , { digit | "_" , digit };
+ * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
+ * extra spaces = ? \s* ? ;
+ *
+ * See String#to_c.
*/
static VALUE
nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
@@ -721,19 +697,14 @@ rb_dbl_complex_new_polar_pi(double abs, double ang)
/*
* call-seq:
- * Complex.polar(abs, arg = 0) -> complex
+ * Complex.polar(abs[, arg]) -> complex
*
- * Returns a new \Complex object formed from the arguments,
- * each of which must be an instance of Numeric,
- * or an instance of one of its subclasses:
- * \Complex, Float, Integer, Rational.
- * Argument +arg+ is given in radians;
- * see {Polar Coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
- *
- * Complex.polar(3) # => (3+0i)
- * Complex.polar(3, 2.0) # => (-1.2484405096414273+2.727892280477045i)
- * Complex.polar(-3, -2.0) # => (1.2484405096414273+2.727892280477045i)
+ * Returns a complex object which denotes the given polar form.
*
+ * Complex.polar(3, 0) #=> (3.0+0.0i)
+ * Complex.polar(3, Math::PI/2) #=> (1.836909530733566e-16+3.0i)
+ * Complex.polar(3, Math::PI) #=> (-3.0+3.673819061467132e-16i)
+ * Complex.polar(3, -Math::PI/2) #=> (1.836909530733566e-16-3.0i)
*/
static VALUE
nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
@@ -753,19 +724,12 @@ nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
- * real -> numeric
- *
- * Returns the real value for +self+:
+ * cmp.real -> real
*
- * Complex(7).real #=> 7
- * Complex(9, -4).real #=> 9
- *
- * If +self+ was created with
- * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.polar(1, Math::PI/4).real # => 0.7071067811865476 # Square root of 2.
+ * Returns the real part.
*
+ * Complex(7).real #=> 7
+ * Complex(9, -4).real #=> 9
*/
VALUE
rb_complex_real(VALUE self)
@@ -776,19 +740,13 @@ rb_complex_real(VALUE self)
/*
* call-seq:
- * imag -> numeric
+ * cmp.imag -> real
+ * cmp.imaginary -> real
*
- * Returns the imaginary value for +self+:
+ * Returns the imaginary part.
*
* Complex(7).imaginary #=> 0
* Complex(9, -4).imaginary #=> -4
- *
- * If +self+ was created with
- * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.polar(1, Math::PI/4).imag # => 0.7071067811865476 # Square root of 2.
- *
*/
VALUE
rb_complex_imag(VALUE self)
@@ -799,13 +757,11 @@ rb_complex_imag(VALUE self)
/*
* call-seq:
- * -complex -> new_complex
- *
- * Returns the negation of +self+, which is the negation of each of its parts:
+ * -cmp -> complex
*
- * -Complex(1, 2) # => (-1-2i)
- * -Complex(-1, -2) # => (1+2i)
+ * Returns negation of the value.
*
+ * -Complex(1, 2) #=> (-1-2i)
*/
VALUE
rb_complex_uminus(VALUE self)
@@ -817,16 +773,15 @@ rb_complex_uminus(VALUE self)
/*
* call-seq:
- * complex + numeric -> new_complex
+ * cmp + numeric -> complex
*
- * Returns the sum of +self+ and +numeric+:
- *
- * Complex(2, 3) + Complex(2, 3) # => (4+6i)
- * Complex(900) + Complex(1) # => (901+0i)
- * Complex(-2, 9) + Complex(-9, 2) # => (-11+11i)
- * Complex(9, 8) + 4 # => (13+8i)
- * Complex(20, 9) + 9.8 # => (29.8+9i)
+ * Performs addition.
*
+ * Complex(2, 3) + Complex(2, 3) #=> (4+6i)
+ * Complex(900) + Complex(1) #=> (901+0i)
+ * Complex(-2, 9) + Complex(-9, 2) #=> (-11+11i)
+ * Complex(9, 8) + 4 #=> (13+8i)
+ * Complex(20, 9) + 9.8 #=> (29.8+9i)
*/
VALUE
rb_complex_plus(VALUE self, VALUE other)
@@ -852,16 +807,15 @@ rb_complex_plus(VALUE self, VALUE other)
/*
* call-seq:
- * complex - numeric -> new_complex
- *
- * Returns the difference of +self+ and +numeric+:
+ * cmp - numeric -> complex
*
- * Complex(2, 3) - Complex(2, 3) # => (0+0i)
- * Complex(900) - Complex(1) # => (899+0i)
- * Complex(-2, 9) - Complex(-9, 2) # => (7+7i)
- * Complex(9, 8) - 4 # => (5+8i)
- * Complex(20, 9) - 9.8 # => (10.2+9i)
+ * Performs subtraction.
*
+ * Complex(2, 3) - Complex(2, 3) #=> (0+0i)
+ * Complex(900) - Complex(1) #=> (899+0i)
+ * Complex(-2, 9) - Complex(-9, 2) #=> (7+7i)
+ * Complex(9, 8) - 4 #=> (5+8i)
+ * Complex(20, 9) - 9.8 #=> (10.2+9i)
*/
VALUE
rb_complex_minus(VALUE self, VALUE other)
@@ -913,16 +867,15 @@ comp_mul(VALUE areal, VALUE aimag, VALUE breal, VALUE bimag, VALUE *real, VALUE
/*
* call-seq:
- * complex * numeric -> new_complex
+ * cmp * numeric -> complex
*
- * Returns the product of +self+ and +numeric+:
- *
- * Complex(2, 3) * Complex(2, 3) # => (-5+12i)
- * Complex(900) * Complex(1) # => (900+0i)
- * Complex(-2, 9) * Complex(-9, 2) # => (0-85i)
- * Complex(9, 8) * 4 # => (36+32i)
- * Complex(20, 9) * 9.8 # => (196.0+88.2i)
+ * Performs multiplication.
*
+ * Complex(2, 3) * Complex(2, 3) #=> (-5+12i)
+ * Complex(900) * Complex(1) #=> (900+0i)
+ * Complex(-2, 9) * Complex(-9, 2) #=> (0-85i)
+ * Complex(9, 8) * 4 #=> (36+32i)
+ * Complex(20, 9) * 9.8 #=> (196.0+88.2i)
*/
VALUE
rb_complex_mul(VALUE self, VALUE other)
@@ -989,16 +942,16 @@ f_divide(VALUE self, VALUE other,
/*
* call-seq:
- * complex / numeric -> new_complex
- *
- * Returns the quotient of +self+ and +numeric+:
+ * cmp / numeric -> complex
+ * cmp.quo(numeric) -> complex
*
- * Complex(2, 3) / Complex(2, 3) # => ((1/1)+(0/1)*i)
- * Complex(900) / Complex(1) # => ((900/1)+(0/1)*i)
- * Complex(-2, 9) / Complex(-9, 2) # => ((36/85)-(77/85)*i)
- * Complex(9, 8) / 4 # => ((9/4)+(2/1)*i)
- * Complex(20, 9) / 9.8 # => (2.0408163265306123+0.9183673469387754i)
+ * Performs division.
*
+ * Complex(2, 3) / Complex(2, 3) #=> ((1/1)+(0/1)*i)
+ * Complex(900) / Complex(1) #=> ((900/1)+(0/1)*i)
+ * Complex(-2, 9) / Complex(-9, 2) #=> ((36/85)-(77/85)*i)
+ * Complex(9, 8) / 4 #=> ((9/4)+(2/1)*i)
+ * Complex(20, 9) / 9.8 #=> (2.0408163265306123+0.9183673469387754i)
*/
VALUE
rb_complex_div(VALUE self, VALUE other)
@@ -1010,12 +963,11 @@ rb_complex_div(VALUE self, VALUE other)
/*
* call-seq:
- * fdiv(numeric) -> new_complex
+ * cmp.fdiv(numeric) -> complex
*
- * Returns <tt>Complex(self.real/numeric, self.imag/numeric)</tt>:
- *
- * Complex(11, 22).fdiv(3) # => (3.6666666666666665+7.333333333333333i)
+ * Performs division as each part is a float, never returns a float.
*
+ * Complex(11, 22).fdiv(3) #=> (3.6666666666666665+7.333333333333333i)
*/
static VALUE
nucomp_fdiv(VALUE self, VALUE other)
@@ -1029,93 +981,14 @@ f_reciprocal(VALUE x)
return f_quo(ONE, x);
}
-static VALUE
-zero_for(VALUE x)
-{
- if (RB_FLOAT_TYPE_P(x))
- return DBL2NUM(0);
- if (RB_TYPE_P(x, T_RATIONAL))
- return rb_rational_new(INT2FIX(0), INT2FIX(1));
-
- return INT2FIX(0);
-}
-
-static VALUE
-complex_pow_for_special_angle(VALUE self, VALUE other)
-{
- if (!rb_integer_type_p(other)) {
- return Qundef;
- }
-
- get_dat1(self);
- VALUE x = Qundef;
- int dir;
- if (f_zero_p(dat->imag)) {
- x = dat->real;
- dir = 0;
- }
- else if (f_zero_p(dat->real)) {
- x = dat->imag;
- dir = 2;
- }
- else if (f_eqeq_p(dat->real, dat->imag)) {
- x = dat->real;
- dir = 1;
- }
- else if (f_eqeq_p(dat->real, f_negate(dat->imag))) {
- x = dat->imag;
- dir = 3;
- }
-
- if (x == Qundef) return x;
-
- if (f_negative_p(x)) {
- x = f_negate(x);
- dir += 4;
- }
-
- VALUE zx;
- if (dir % 2 == 0) {
- zx = rb_num_pow(x, other);
- }
- else {
- zx = rb_num_pow(
- rb_funcall(rb_int_mul(TWO, x), '*', 1, x),
- rb_int_div(other, TWO)
- );
- if (rb_int_odd_p(other)) {
- zx = rb_funcall(zx, '*', 1, x);
- }
- }
- static const int dirs[][2] = {
- {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}
- };
- int z_dir = FIX2INT(rb_int_modulo(rb_int_mul(INT2FIX(dir), other), INT2FIX(8)));
-
- VALUE zr = Qfalse, zi = Qfalse;
- switch (dirs[z_dir][0]) {
- case 0: zr = zero_for(zx); break;
- case 1: zr = zx; break;
- case -1: zr = f_negate(zx); break;
- }
- switch (dirs[z_dir][1]) {
- case 0: zi = zero_for(zx); break;
- case 1: zi = zx; break;
- case -1: zi = f_negate(zx); break;
- }
- return nucomp_s_new_internal(CLASS_OF(self), zr, zi);
-}
-
-
/*
* call-seq:
- * complex ** numeric -> new_complex
- *
- * Returns +self+ raised to power +numeric+:
+ * cmp ** numeric -> complex
*
- * Complex('i') ** 2 # => (-1+0i)
- * Complex(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i)
+ * Performs exponentiation.
*
+ * Complex('i') ** 2 #=> (-1+0i)
+ * Complex(-8) ** Rational(1, 3) #=> (1.0000000000000002+1.7320508075688772i)
*/
VALUE
rb_complex_pow(VALUE self, VALUE other)
@@ -1133,14 +1006,6 @@ rb_complex_pow(VALUE self, VALUE other)
other = dat->real; /* c14n */
}
- if (other == ONE) {
- get_dat1(self);
- return nucomp_s_new_internal(CLASS_OF(self), dat->real, dat->imag);
- }
-
- VALUE result = complex_pow_for_special_angle(self, other);
- if (result != Qundef) return result;
-
if (RB_TYPE_P(other, T_COMPLEX)) {
VALUE r, theta, nr, ntheta;
@@ -1213,13 +1078,15 @@ rb_complex_pow(VALUE self, VALUE other)
/*
* call-seq:
- * complex == object -> true or false
+ * cmp == object -> true or false
*
- * Returns +true+ if <tt>self.real == object.real</tt>
- * and <tt>self.imag == object.imag</tt>:
- *
- * Complex(2, 3) == Complex(2.0, 3.0) # => true
+ * Returns true if cmp equals object numerically.
*
+ * Complex(2, 3) == Complex(2, 3) #=> true
+ * Complex(5) == 5 #=> true
+ * Complex(0) == 0.0 #=> true
+ * Complex('1/3') == 0.33 #=> false
+ * Complex('1/2') == '1/2' #=> false
*/
static VALUE
nucomp_eqeq_p(VALUE self, VALUE other)
@@ -1247,26 +1114,17 @@ nucomp_real_p(VALUE self)
/*
* call-seq:
- * complex <=> object -> -1, 0, 1, or nil
- *
- * Returns:
- *
- * - <tt>self.real <=> object.real</tt> if both of the following are true:
- *
- * - <tt>self.imag == 0</tt>.
- * - <tt>object.imag == 0</tt>. # Always true if object is numeric but not complex.
- *
- * - +nil+ otherwise.
+ * cmp <=> object -> 0, 1, -1, or nil
*
- * Examples:
- *
- * Complex(2) <=> 3 # => -1
- * Complex(2) <=> 2 # => 0
- * Complex(2) <=> 1 # => 1
- * Complex(2, 1) <=> 1 # => nil # self.imag not zero.
- * Complex(1) <=> Complex(1, 1) # => nil # object.imag not zero.
- * Complex(1) <=> 'Foo' # => nil # object.imag not defined.
+ * If +cmp+'s imaginary part is zero, and +object+ is also a
+ * real number (or a Complex number where the imaginary part is zero),
+ * compare the real part of +cmp+ to object. Otherwise, return nil.
*
+ * Complex(2, 3) <=> Complex(2, 3) #=> nil
+ * Complex(2, 3) <=> 1 #=> nil
+ * Complex(2) <=> 1 #=> 1
+ * Complex(2) <=> 2 #=> 0
+ * Complex(2) <=> 3 #=> -1
*/
static VALUE
nucomp_cmp(VALUE self, VALUE other)
@@ -1311,19 +1169,13 @@ nucomp_coerce(VALUE self, VALUE other)
/*
* call-seq:
- * abs -> float
- *
- * Returns the absolute value (magnitude) for +self+;
- * see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
- *
- * Complex.polar(-1, 0).abs # => 1.0
- *
- * If +self+ was created with
- * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
- * is computed, and may be inexact:
+ * cmp.abs -> real
+ * cmp.magnitude -> real
*
- * Complex.rectangular(1, 1).abs # => 1.4142135623730951 # The square root of 2.
+ * Returns the absolute part of its polar form.
*
+ * Complex(-1).abs #=> 1
+ * Complex(3.0, -4.0).abs #=> 5.0
*/
VALUE
rb_complex_abs(VALUE self)
@@ -1347,19 +1199,12 @@ rb_complex_abs(VALUE self)
/*
* call-seq:
- * abs2 -> float
+ * cmp.abs2 -> real
*
- * Returns square of the absolute value (magnitude) for +self+;
- * see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
- *
- * Complex.polar(2, 2).abs2 # => 4.0
- *
- * If +self+ was created with
- * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.rectangular(1.0/3, 1.0/3).abs2 # => 0.2222222222222222
+ * Returns square of the absolute value.
*
+ * Complex(-1).abs2 #=> 1
+ * Complex(3.0, -4.0).abs2 #=> 25.0
*/
static VALUE
nucomp_abs2(VALUE self)
@@ -1371,19 +1216,13 @@ nucomp_abs2(VALUE self)
/*
* call-seq:
- * arg -> float
- *
- * Returns the argument (angle) for +self+ in radians;
- * see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
+ * cmp.arg -> float
+ * cmp.angle -> float
+ * cmp.phase -> float
*
- * Complex.polar(3, Math::PI/2).arg # => 1.57079632679489660
- *
- * If +self+ was created with
- * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.polar(1, 1.0/3).arg # => 0.33333333333333326
+ * Returns the angle part of its polar form.
*
+ * Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
*/
VALUE
rb_complex_arg(VALUE self)
@@ -1394,22 +1233,12 @@ rb_complex_arg(VALUE self)
/*
* call-seq:
- * rect -> array
- *
- * Returns the array <tt>[self.real, self.imag]</tt>:
- *
- * Complex.rect(1, 2).rect # => [1, 2]
+ * cmp.rect -> array
+ * cmp.rectangular -> array
*
- * See {Rectangular Coordinates}[rdoc-ref:Complex@Rectangular+Coordinates].
+ * Returns an array; [cmp.real, cmp.imag].
*
- * If +self+ was created with
- * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.polar(1.0, 1.0).rect # => [0.5403023058681398, 0.8414709848078965]
- *
- *
- * Complex#rectangular is an alias for Complex#rect.
+ * Complex(1, 2).rectangular #=> [1, 2]
*/
static VALUE
nucomp_rect(VALUE self)
@@ -1420,20 +1249,11 @@ nucomp_rect(VALUE self)
/*
* call-seq:
- * polar -> array
- *
- * Returns the array <tt>[self.abs, self.arg]</tt>:
+ * cmp.polar -> array
*
- * Complex.polar(1, 2).polar # => [1.0, 2.0]
- *
- * See {Polar Coordinates}[rdoc-ref:Complex@Polar+Coordinates].
- *
- * If +self+ was created with
- * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.rect(1, 1).polar # => [1.4142135623730951, 0.7853981633974483]
+ * Returns an array; [cmp.abs, cmp.arg].
*
+ * Complex(1, 2).polar #=> [2.23606797749979, 1.1071487177940904]
*/
static VALUE
nucomp_polar(VALUE self)
@@ -1443,12 +1263,12 @@ nucomp_polar(VALUE self)
/*
* call-seq:
- * conj -> complex
- *
- * Returns the conjugate of +self+, <tt>Complex.rect(self.imag, self.real)</tt>:
+ * cmp.conj -> complex
+ * cmp.conjugate -> complex
*
- * Complex.rect(1, 2).conj # => (1-2i)
+ * Returns the complex conjugate.
*
+ * Complex(1, 2).conjugate #=> (1-2i)
*/
VALUE
rb_complex_conjugate(VALUE self)
@@ -1459,9 +1279,10 @@ rb_complex_conjugate(VALUE self)
/*
* call-seq:
- * real? -> false
+ * Complex(1).real? -> false
+ * Complex(1, 2).real? -> false
*
- * Returns +false+; for compatibility with Numeric#real?.
+ * Returns false, even if the complex number has no imaginary part.
*/
static VALUE
nucomp_real_p_m(VALUE self)
@@ -1471,17 +1292,11 @@ nucomp_real_p_m(VALUE self)
/*
* call-seq:
- * denominator -> integer
+ * cmp.denominator -> integer
*
- * Returns the denominator of +self+, which is
- * the {least common multiple}[https://en.wikipedia.org/wiki/Least_common_multiple]
- * of <tt>self.real.denominator</tt> and <tt>self.imag.denominator</tt>:
+ * Returns the denominator (lcm of both denominator - real and imag).
*
- * Complex.rect(Rational(1, 2), Rational(2, 3)).denominator # => 6
- *
- * Note that <tt>n.denominator</tt> of a non-rational numeric is +1+.
- *
- * Related: Complex#numerator.
+ * See numerator.
*/
static VALUE
nucomp_denominator(VALUE self)
@@ -1492,23 +1307,21 @@ nucomp_denominator(VALUE self)
/*
* call-seq:
- * numerator -> new_complex
+ * cmp.numerator -> numeric
*
- * Returns the \Complex object created from the numerators
- * of the real and imaginary parts of +self+,
- * after converting each part to the
- * {lowest common denominator}[https://en.wikipedia.org/wiki/Lowest_common_denominator]
- * of the two:
+ * Returns the numerator.
*
- * c = Complex(Rational(2, 3), Rational(3, 4)) # => ((2/3)+(3/4)*i)
- * c.numerator # => (8+9i)
+ * 1 2 3+4i <- numerator
+ * - + -i -> ----
+ * 2 3 6 <- denominator
*
- * In this example, the lowest common denominator of the two parts is 12;
- * the two converted parts may be thought of as \Rational(8, 12) and \Rational(9, 12),
- * whose numerators, respectively, are 8 and 9;
- * so the returned value of <tt>c.numerator</tt> is <tt>Complex(8, 9)</tt>.
- *
- * Related: Complex#denominator.
+ * c = Complex('1/2+2/3i') #=> ((1/2)+(2/3)*i)
+ * n = c.numerator #=> (3+4i)
+ * d = c.denominator #=> 6
+ * n / d #=> ((1/2)+(2/3)*i)
+ * Complex(Rational(n.real, d), Rational(n.imag, d))
+ * #=> ((1/2)+(2/3)*i)
+ * See denominator.
*/
static VALUE
nucomp_numerator(VALUE self)
@@ -1541,18 +1354,6 @@ rb_complex_hash(VALUE self)
return v;
}
-/*
- * :call-seq:
- * hash -> integer
- *
- * Returns the integer hash value for +self+.
- *
- * Two \Complex objects created from the same values will have the same hash value
- * (and will compare using #eql?):
- *
- * Complex(1, 2).hash == Complex(1, 2).hash # => true
- *
- */
static VALUE
nucomp_hash(VALUE self)
{
@@ -1613,16 +1414,15 @@ f_format(VALUE self, VALUE (*func)(VALUE))
/*
* call-seq:
- * to_s -> string
- *
- * Returns a string representation of +self+:
+ * cmp.to_s -> string
*
- * Complex(2).to_s # => "2+0i"
- * Complex('-8/6').to_s # => "-4/3+0i"
- * Complex('1/2i').to_s # => "0+1/2i"
- * Complex(0, Float::INFINITY).to_s # => "0+Infinity*i"
- * Complex(Float::NAN, Float::NAN).to_s # => "NaN+NaN*i"
+ * Returns the value as a string.
*
+ * Complex(2).to_s #=> "2+0i"
+ * Complex('-8/6').to_s #=> "-4/3+0i"
+ * Complex('1/2i').to_s #=> "0+1/2i"
+ * Complex(0, Float::INFINITY).to_s #=> "0+Infinity*i"
+ * Complex(Float::NAN, Float::NAN).to_s #=> "NaN+NaN*i"
*/
static VALUE
nucomp_to_s(VALUE self)
@@ -1632,16 +1432,15 @@ nucomp_to_s(VALUE self)
/*
* call-seq:
- * inspect -> string
- *
- * Returns a string representation of +self+:
+ * cmp.inspect -> string
*
- * Complex(2).inspect # => "(2+0i)"
- * Complex('-8/6').inspect # => "((-4/3)+0i)"
- * Complex('1/2i').inspect # => "(0+(1/2)*i)"
- * Complex(0, Float::INFINITY).inspect # => "(0+Infinity*i)"
- * Complex(Float::NAN, Float::NAN).inspect # => "(NaN+NaN*i)"
+ * Returns the value as a string for inspection.
*
+ * Complex(2).inspect #=> "(2+0i)"
+ * Complex('-8/6').inspect #=> "((-4/3)+0i)"
+ * Complex('1/2i').inspect #=> "(0+(1/2)*i)"
+ * Complex(0, Float::INFINITY).inspect #=> "(0+Infinity*i)"
+ * Complex(Float::NAN, Float::NAN).inspect #=> "(NaN+NaN*i)"
*/
static VALUE
nucomp_inspect(VALUE self)
@@ -1659,15 +1458,10 @@ nucomp_inspect(VALUE self)
/*
* call-seq:
- * finite? -> true or false
- *
- * Returns +true+ if both <tt>self.real.finite?</tt> and <tt>self.imag.finite?</tt>
- * are true, +false+ otherwise:
- *
- * Complex(1, 1).finite? # => true
- * Complex(Float::INFINITY, 0).finite? # => false
+ * cmp.finite? -> true or false
*
- * Related: Numeric#finite?, Float#finite?.
+ * Returns +true+ if +cmp+'s real and imaginary parts are both finite numbers,
+ * otherwise returns +false+.
*/
static VALUE
rb_complex_finite_p(VALUE self)
@@ -1679,15 +1473,15 @@ rb_complex_finite_p(VALUE self)
/*
* call-seq:
- * infinite? -> 1 or nil
+ * cmp.infinite? -> nil or 1
*
- * Returns +1+ if either <tt>self.real.infinite?</tt> or <tt>self.imag.infinite?</tt>
- * is true, +nil+ otherwise:
+ * Returns +1+ if +cmp+'s real or imaginary part is an infinite number,
+ * otherwise returns +nil+.
*
- * Complex(Float::INFINITY, 0).infinite? # => 1
- * Complex(1, 1).infinite? # => nil
+ * For example:
*
- * Related: Numeric#infinite?, Float#infinite?.
+ * (1+1i).infinite? #=> nil
+ * (Float::INFINITY + 1i).infinite? #=> 1
*/
static VALUE
rb_complex_infinite_p(VALUE self)
@@ -1785,15 +1579,14 @@ rb_dbl_complex_new(double real, double imag)
/*
* call-seq:
- * to_i -> integer
- *
- * Returns the value of <tt>self.real</tt> as an Integer, if possible:
+ * cmp.to_i -> integer
*
- * Complex(1, 0).to_i # => 1
- * Complex(1, Rational(0, 1)).to_i # => 1
+ * Returns the value as an integer if possible (the imaginary part
+ * should be exactly zero).
*
- * Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
+ * Complex(1, 0).to_i #=> 1
+ * Complex(1, 0.0).to_i # RangeError
+ * Complex(1, 2).to_i # RangeError
*/
static VALUE
nucomp_to_i(VALUE self)
@@ -1809,15 +1602,14 @@ nucomp_to_i(VALUE self)
/*
* call-seq:
- * to_f -> float
+ * cmp.to_f -> float
*
- * Returns the value of <tt>self.real</tt> as a Float, if possible:
+ * Returns the value as a float if possible (the imaginary part should
+ * be exactly zero).
*
- * Complex(1, 0).to_f # => 1.0
- * Complex(1, Rational(0, 1)).to_f # => 1.0
- *
- * Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
+ * Complex(1, 0).to_f #=> 1.0
+ * Complex(1, 0.0).to_f # RangeError
+ * Complex(1, 2).to_f # RangeError
*/
static VALUE
nucomp_to_f(VALUE self)
@@ -1833,17 +1625,16 @@ nucomp_to_f(VALUE self)
/*
* call-seq:
- * to_r -> rational
- *
- * Returns the value of <tt>self.real</tt> as a Rational, if possible:
+ * cmp.to_r -> rational
*
- * Complex(1, 0).to_r # => (1/1)
- * Complex(1, Rational(0, 1)).to_r # => (1/1)
+ * Returns the value as a rational if possible (the imaginary part
+ * should be exactly zero).
*
- * Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
+ * Complex(1, 0).to_r #=> (1/1)
+ * Complex(1, 0.0).to_r # RangeError
+ * Complex(1, 2).to_r # RangeError
*
- * Related: Complex#rationalize.
+ * See rationalize.
*/
static VALUE
nucomp_to_r(VALUE self)
@@ -1859,35 +1650,16 @@ nucomp_to_r(VALUE self)
/*
* call-seq:
- * rationalize(epsilon = nil) -> rational
- *
- * Returns a Rational object whose value is exactly or approximately
- * equivalent to that of <tt>self.real</tt>.
- *
- * With no argument +epsilon+ given, returns a \Rational object
- * whose value is exactly equal to that of <tt>self.real.rationalize</tt>:
- *
- * Complex(1, 0).rationalize # => (1/1)
- * Complex(1, Rational(0, 1)).rationalize # => (1/1)
- * Complex(3.14159, 0).rationalize # => (314159/100000)
- *
- * With argument +epsilon+ given, returns a \Rational object
- * whose value is exactly or approximately equal to that of <tt>self.real</tt>
- * to the given precision:
- *
- * Complex(3.14159, 0).rationalize(0.1) # => (16/5)
- * Complex(3.14159, 0).rationalize(0.01) # => (22/7)
- * Complex(3.14159, 0).rationalize(0.001) # => (201/64)
- * Complex(3.14159, 0).rationalize(0.0001) # => (333/106)
- * Complex(3.14159, 0).rationalize(0.00001) # => (355/113)
- * Complex(3.14159, 0).rationalize(0.000001) # => (7433/2366)
- * Complex(3.14159, 0).rationalize(0.0000001) # => (9208/2931)
- * Complex(3.14159, 0).rationalize(0.00000001) # => (47460/15107)
- * Complex(3.14159, 0).rationalize(0.000000001) # => (76149/24239)
- * Complex(3.14159, 0).rationalize(0.0000000001) # => (314159/100000)
- * Complex(3.14159, 0).rationalize(0.0) # => (3537115888337719/1125899906842624)
- *
- * Related: Complex#to_r.
+ * cmp.rationalize([eps]) -> rational
+ *
+ * Returns the value as a rational if possible (the imaginary part
+ * should be exactly zero).
+ *
+ * Complex(1.0/3, 0).rationalize #=> (1/3)
+ * Complex(1, 0.0).rationalize # RangeError
+ * Complex(1, 2).rationalize # RangeError
+ *
+ * See to_r.
*/
static VALUE
nucomp_rationalize(int argc, VALUE *argv, VALUE self)
@@ -1905,9 +1677,12 @@ nucomp_rationalize(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * to_c -> self
+ * complex.to_c -> self
+ *
+ * Returns self.
*
- * Returns +self+.
+ * Complex(2).to_c #=> (2+0i)
+ * Complex(-8, 6).to_c #=> (-8+6i)
*/
static VALUE
nucomp_to_c(VALUE self)
@@ -1917,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)
@@ -1932,9 +1704,9 @@ nilclass_to_c(VALUE self)
/*
* call-seq:
- * to_c -> complex
+ * num.to_c -> complex
*
- * Returns +self+ as a Complex object.
+ * Returns the value as a complex.
*/
static VALUE
numeric_to_c(VALUE self)
@@ -2214,14 +1986,23 @@ string_to_c_strict(VALUE self, int raise)
rb_must_asciicompat(self);
- if (raise) {
- s = StringValueCStr(self);
+ s = RSTRING_PTR(self);
+
+ if (!s || memchr(s, '\0', RSTRING_LEN(self))) {
+ if (!raise) return Qnil;
+ rb_raise(rb_eArgError, "string contains null byte");
}
- else if (!(s = rb_str_to_cstr(self))) {
- return Qnil;
+
+ if (s && s[RSTRING_LEN(self)]) {
+ rb_str_modify(self);
+ s = RSTRING_PTR(self);
+ s[RSTRING_LEN(self)] = '\0';
}
- if (!parse_comp(s, TRUE, &num)) {
+ if (!s)
+ s = (char *)"";
+
+ if (!parse_comp(s, 1, &num)) {
if (!raise) return Qnil;
rb_raise(rb_eArgError, "invalid value for convert(): %+"PRIsVALUE,
self);
@@ -2232,39 +2013,53 @@ string_to_c_strict(VALUE self, int raise)
/*
* call-seq:
- * to_c -> complex
- *
- * Returns +self+ interpreted as a Complex object;
- * leading whitespace and trailing garbage are ignored:
- *
- * '9'.to_c # => (9+0i)
- * '2.5'.to_c # => (2.5+0i)
- * '2.5/1'.to_c # => ((5/2)+0i)
- * '-3/2'.to_c # => ((-3/2)+0i)
- * '-i'.to_c # => (0-1i)
- * '45i'.to_c # => (0+45i)
- * '3-4i'.to_c # => (3-4i)
- * '-4e2-4e-2i'.to_c # => (-400.0-0.04i)
- * '-0.0-0.0i'.to_c # => (-0.0-0.0i)
- * '1/2+3/4i'.to_c # => ((1/2)+(3/4)*i)
- * '1.0@0'.to_c # => (1+0.0i)
- * "1.0@#{Math::PI/2}".to_c # => (0.0+1i)
- * "1.0@#{Math::PI}".to_c # => (-1+0.0i)
- *
- * Returns \Complex zero if the string cannot be converted:
- *
- * 'ruby'.to_c # => (0+0i)
- *
- * See Kernel#Complex.
+ * str.to_c -> complex
+ *
+ * Returns a complex which denotes the string form. The parser
+ * ignores leading whitespaces and trailing garbage. Any digit
+ * sequences can be separated by an underscore. Returns zero for null
+ * or garbage string.
+ *
+ * '9'.to_c #=> (9+0i)
+ * '2.5'.to_c #=> (2.5+0i)
+ * '2.5/1'.to_c #=> ((5/2)+0i)
+ * '-3/2'.to_c #=> ((-3/2)+0i)
+ * '-i'.to_c #=> (0-1i)
+ * '45i'.to_c #=> (0+45i)
+ * '3-4i'.to_c #=> (3-4i)
+ * '-4e2-4e-2i'.to_c #=> (-400.0-0.04i)
+ * '-0.0-0.0i'.to_c #=> (-0.0-0.0i)
+ * '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i)
+ * 'ruby'.to_c #=> (0+0i)
+ *
+ * Polar form:
+ * include Math
+ * "1.0@0".to_c #=> (1+0.0i)
+ * "1.0@#{PI/2}".to_c #=> (0.0+1i)
+ * "1.0@#{PI}".to_c #=> (-1+0.0i)
+ *
+ * See Kernel.Complex.
*/
static VALUE
string_to_c(VALUE self)
{
+ char *s;
VALUE num;
rb_must_asciicompat(self);
- (void)parse_comp(rb_str_fill_terminator(self, 1), FALSE, &num);
+ s = RSTRING_PTR(self);
+
+ if (s && s[RSTRING_LEN(self)]) {
+ rb_str_modify(self);
+ s = RSTRING_PTR(self);
+ s[RSTRING_LEN(self)] = '\0';
+ }
+
+ if (!s)
+ s = (char *)"";
+
+ (void)parse_comp(s, 0, &num);
return num;
}
@@ -2321,11 +2116,8 @@ nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
return a1;
/* should raise exception for consistency */
if (!k_numeric_p(a1)) {
- if (!raise) {
- a1 = rb_protect(to_complex, a1, NULL);
- rb_set_errinfo(Qnil);
- return a1;
- }
+ if (!raise)
+ return rb_protect(to_complex, a1, NULL);
return to_complex(a1);
}
}
@@ -2369,9 +2161,9 @@ nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
- * abs2 -> real
+ * num.abs2 -> real
*
- * Returns the square of +self+.
+ * Returns square of self.
*/
static VALUE
numeric_abs2(VALUE self)
@@ -2381,9 +2173,11 @@ numeric_abs2(VALUE self)
/*
* call-seq:
- * arg -> 0 or Math::PI
+ * num.arg -> 0 or float
+ * num.angle -> 0 or float
+ * num.phase -> 0 or float
*
- * Returns zero if +self+ is positive, Math::PI otherwise.
+ * Returns 0 if the value is positive, pi otherwise.
*/
static VALUE
numeric_arg(VALUE self)
@@ -2395,9 +2189,10 @@ numeric_arg(VALUE self)
/*
* call-seq:
- * rect -> array
+ * num.rect -> array
+ * num.rectangular -> array
*
- * Returns array <tt>[self, 0]</tt>.
+ * Returns an array; [num, 0].
*/
static VALUE
numeric_rect(VALUE self)
@@ -2407,9 +2202,9 @@ numeric_rect(VALUE self)
/*
* call-seq:
- * polar -> array
+ * num.polar -> array
*
- * Returns array <tt>[self.abs, self.arg]</tt>.
+ * Returns an array; [num.abs, num.arg].
*/
static VALUE
numeric_polar(VALUE self)
@@ -2437,9 +2232,11 @@ numeric_polar(VALUE self)
/*
* call-seq:
- * arg -> 0 or Math::PI
+ * flo.arg -> 0 or float
+ * flo.angle -> 0 or float
+ * flo.phase -> 0 or float
*
- * Returns 0 if +self+ is positive, Math::PI otherwise.
+ * Returns 0 if the value is positive, pi otherwise.
*/
static VALUE
float_arg(VALUE self)
@@ -2452,63 +2249,45 @@ float_arg(VALUE self)
}
/*
- * A \Complex object houses a pair of values,
- * given when the object is created as either <i>rectangular coordinates</i>
- * or <i>polar coordinates</i>.
- *
- * == Rectangular Coordinates
- *
- * The rectangular coordinates of a complex number
- * are called the _real_ and _imaginary_ parts;
- * see {Complex number definition}[https://en.wikipedia.org/wiki/Complex_number#Definition].
- *
- * You can create a \Complex object from rectangular coordinates with:
- *
- * - A {complex literal}[rdoc-ref:doc/syntax/literals.rdoc@Complex+Literals].
- * - \Method Complex.rect.
- * - \Method Kernel#Complex, either with numeric arguments or with certain string arguments.
- * - \Method String#to_c, for certain strings.
- *
- * Note that each of the stored parts may be a an instance one of the classes
- * Complex, Float, Integer, or Rational;
- * they may be retrieved:
- *
- * - Separately, with methods Complex#real and Complex#imaginary.
- * - Together, with method Complex#rect.
- *
- * The corresponding (computed) polar values may be retrieved:
+ * A complex number can be represented as a paired real number with
+ * imaginary unit; a+bi. Where a is real part, b is imaginary part
+ * and i is imaginary unit. Real a equals complex a+0i
+ * mathematically.
*
- * - Separately, with methods Complex#abs and Complex#arg.
- * - Together, with method Complex#polar.
+ * You can create a \Complex object explicitly with:
*
- * == Polar Coordinates
+ * - A {complex literal}[rdoc-ref:syntax/literals.rdoc@Complex+Literals].
*
- * The polar coordinates of a complex number
- * are called the _absolute_ and _argument_ parts;
- * see {Complex polar plane}[https://en.wikipedia.org/wiki/Complex_number#Polar_complex_plane].
+ * You can convert certain objects to \Complex objects with:
*
- * In this class, the argument part
- * in expressed {radians}[https://en.wikipedia.org/wiki/Radian]
- * (not {degrees}[https://en.wikipedia.org/wiki/Degree_(angle)]).
+ * - \Method #Complex.
*
- * You can create a \Complex object from polar coordinates with:
+ * Complex object can be created as literal, and also by using
+ * Kernel#Complex, Complex::rect, Complex::polar or to_c method.
*
- * - \Method Complex.polar.
- * - \Method Kernel#Complex, with certain string arguments.
- * - \Method String#to_c, for certain strings.
+ * 2+1i #=> (2+1i)
+ * Complex(1) #=> (1+0i)
+ * Complex(2, 3) #=> (2+3i)
+ * Complex.polar(2, 3) #=> (-1.9799849932008908+0.2822400161197344i)
+ * 3.to_c #=> (3+0i)
*
- * Note that each of the stored parts may be a an instance one of the classes
- * Complex, Float, Integer, or Rational;
- * they may be retrieved:
+ * You can also create complex object from floating-point numbers or
+ * strings.
*
- * - Separately, with methods Complex#abs and Complex#arg.
- * - Together, with method Complex#polar.
+ * Complex(0.3) #=> (0.3+0i)
+ * Complex('0.3-0.5i') #=> (0.3-0.5i)
+ * Complex('2/3+3/4i') #=> ((2/3)+(3/4)*i)
+ * Complex('1@2') #=> (-0.4161468365471424+0.9092974268256817i)
*
- * The corresponding (computed) rectangular values may be retrieved:
+ * 0.3.to_c #=> (0.3+0i)
+ * '0.3-0.5i'.to_c #=> (0.3-0.5i)
+ * '2/3+3/4i'.to_c #=> ((2/3)+(3/4)*i)
+ * '1@2'.to_c #=> (-0.4161468365471424+0.9092974268256817i)
*
- * - Separately, with methods Complex#real and Complex#imag.
- * - Together, with method Complex#rect.
+ * A complex object is either an exact or an inexact number.
*
+ * Complex(1, 1) / 2 #=> ((1/2)+(1/2)*i)
+ * Complex(1, 1) / 2.0 #=> (0.5+0.5i)
*/
void
Init_Complex(void)
@@ -2629,11 +2408,7 @@ Init_Complex(void)
rb_define_method(rb_cFloat, "phase", float_arg, 0);
/*
- * Equivalent
- * to <tt>Complex(0, 1)</tt>:
- *
- * Complex::I # => (0+1i)
- *
+ * The imaginary unit.
*/
rb_define_const(rb_cComplex, "I",
f_complex_new_bang2(rb_cComplex, ZERO, ONE));
diff --git a/configure.ac b/configure.ac
index 3b5ea5bade..218c441ff7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,7 +16,6 @@ m4_include([tool/m4/ruby_append_option.m4])dnl
m4_include([tool/m4/ruby_append_options.m4])dnl
m4_include([tool/m4/ruby_check_builtin_func.m4])dnl
m4_include([tool/m4/ruby_check_builtin_setjmp.m4])dnl
-m4_include([tool/m4/ruby_check_header.m4])dnl
m4_include([tool/m4/ruby_check_printf_prefix.m4])dnl
m4_include([tool/m4/ruby_check_setjmp.m4])dnl
m4_include([tool/m4/ruby_check_signedness.m4])dnl
@@ -48,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,
@@ -76,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
], [
@@ -90,7 +78,7 @@ AS_IF([test "$HAVE_BASERUBY" != no -a "`RUBYOPT=- $BASERUBY --disable=gems -e 'p
])
AS_IF([test "$HAVE_BASERUBY" = no], [
AS_IF([test "$cross_compiling" = yes], [AC_MSG_ERROR([executable host ruby is required for cross-compiling])])
- BASERUBY=$srcdir/tool/missing-baseruby.bat
+ BASERUBY="echo executable host ruby is required. use --with-baseruby option.; false"
])
AC_SUBST(BASERUBY)
AC_SUBST(HAVE_BASERUBY)
@@ -226,23 +214,15 @@ 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_prefix}ar/])
-# RUBY_CHECK_PROG_FOR_CC([AS], [s/clang/${llvm_prefix}as/])
+ : ${LD:="${CC}"} # ... try -fuse-ld=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([CXX], [s/clang/clang++/])
- 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/])
+ 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/])
])
AS_UNSET(rb_CC)
AS_UNSET(rb_dummy)
@@ -255,7 +235,7 @@ AS_CASE(["${build_os}"],
AC_PATH_TOOL([NM], [nm], [/usr/ccs/bin/nm], [/usr/ccs/bin:$PATH])
])
AS_CASE(["${target_os}"],
-[cygwin*|msys*|mingw*|darwin*], [
+[cygwin*|msys*|mingw*], [
ac_cv_prog_ac_ct_OBJCOPY=":"
])
@@ -274,14 +254,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)
@@ -390,6 +366,12 @@ AS_CASE(["$target_os"],
[AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)
AC_MSG_ERROR([Unsupported OS X version is required])])
+ 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)])
])
RUBY_MINGW32
@@ -423,17 +405,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"
])
@@ -464,8 +458,8 @@ AC_SUBST(CC_VERSION_MESSAGE, $cc_version_message)
: ${DLDFLAGS="$LDFLAGS"}
RUBY_UNIVERSAL_ARCH
-AS_IF([test "$target_cpu" != "$host_cpu" -a "$GCC" = yes -a "${universal_binary:-no}" = no], [
- RUBY_DEFAULT_ARCH($target_cpu)
+AS_IF([test "$target_cpu" != "$host_cpu" -a "$GCC" = yes -a "$cross_compiling" = no -a "${universal_binary:-no}" = no], [
+ RUBY_DEFAULT_ARCH("$target_cpu")
])
host_os=$target_os
host_vendor=$target_vendor
@@ -509,7 +503,6 @@ AS_CASE(["$target_os"],
])
rb_cv_binary_elf=no
: ${enable_shared=yes}
- AS_IF([$WINDRES --version | grep LLVM > /dev/null], [USE_LLVM_WINDRES=yes], [USE_LLVM_WINDRES=no])
],
[hiuxmpp*], [AC_DEFINE(__HIUX_MPP__)]) # by TOYODA Eizi <toyoda@npd.kishou.go.jp>
@@ -593,7 +586,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 +681,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 +692,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 +796,8 @@ AS_IF([test "$GCC" = yes], [
[@%:@include <stdio.h>])
])
+ : ${MJIT_HEADER_FLAGS='-P -dD'}
+
# -fstack-protector
AS_CASE(["$target_os"],
[emscripten*|wasi*], [
@@ -833,10 +825,7 @@ AS_IF([test "$GCC" = yes], [
AS_FOR(option, opt, [-mbranch-protection=pac-ret -msign-return-address=all], [
RUBY_TRY_CFLAGS(option, [branch_protection=yes], [branch_protection=no])
AS_IF([test "x$branch_protection" = xyes], [
- # C compiler and assembler must be consistent for -mbranch-protection
- # since they both check `__ARM_FEATURE_PAC_DEFAULT` definition.
RUBY_APPEND_OPTION(XCFLAGS, option)
- RUBY_APPEND_OPTION(ASFLAGS, option)
break
])
])
@@ -912,6 +901,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], [
@@ -976,10 +966,9 @@ AS_IF([test "x$OPT_DIR" != x], [
LDFLAGS="${LDFLAGS:+$LDFLAGS }$val"
DLDFLAGS="${DLDFLAGS:+$DLDFLAGS }$val"
LDFLAGS_OPTDIR="$val"
- INCFLAGS="${INCFLAGS:+$INCFLAGS }"`echo "$OPT_DIR" | tr "${PATH_SEPARATOR}" '\012' |
+ CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }"`echo "$OPT_DIR" | tr "${PATH_SEPARATOR}" '\012' |
sed '/^$/d;s|^|-I|;s|$|/include|' | tr '\012' ' ' | sed 's/ *$//'`
])
-AC_SUBST(incflags, "$INCFLAGS")
test -z "${ac_env_CFLAGS_set}" -a -n "${cflags+set}" && eval CFLAGS="\"$cflags $ARCH_FLAG\""
test -z "${ac_env_CXXFLAGS_set}" -a -n "${cxxflags+set}" && eval CXXFLAGS="\"$cxxflags $ARCH_FLAG\""
@@ -994,7 +983,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"])
@@ -1097,18 +1086,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
@@ -1255,7 +1238,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
@@ -1357,17 +1340,13 @@ 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(sys/event.h)
-AC_CHECK_HEADERS(stdatomic.h)
-
AS_CASE("$target_cpu", [x64|x86_64|i[3-6]86*], [
AC_CHECK_HEADERS(x86intrin.h)
])
RUBY_UNIVERSAL_CHECK_HEADER([x86_64, i386], x86intrin.h)
AS_IF([test "x$with_gmp" != xno],
- [RUBY_CHECK_HEADER(gmp.h)
+ [AC_CHECK_HEADERS(gmp.h)
AS_IF([test "x$ac_cv_header_gmp_h" != xno],
AC_SEARCH_LIBS([__gmpz_init], [gmp],
[AC_DEFINE(HAVE_LIBGMP, 1)]))])
@@ -1377,8 +1356,6 @@ 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])
@@ -1410,8 +1387,6 @@ 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],
@@ -1498,25 +1473,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
@@ -1529,9 +1485,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], [
@@ -2040,7 +1997,6 @@ 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)
@@ -2064,7 +2020,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)
@@ -2122,7 +2077,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)
@@ -2176,7 +2130,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)
@@ -2201,6 +2154,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([[
@@ -2269,27 +2225,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([[
@@ -2677,9 +2612,6 @@ AS_CASE([$coroutine_type], [yes|''], [
[*86-mingw*], [
coroutine_type=win32
],
- [aarch64-mingw*], [
- coroutine_type=arm64
- ],
[arm*-linux*], [
coroutine_type=arm32
],
@@ -2692,9 +2624,6 @@ AS_CASE([$coroutine_type], [yes|''], [
[riscv64-linux*], [
coroutine_type=riscv64
],
- [loongarch64-linux*], [
- coroutine_type=loongarch64
- ],
[x86_64-freebsd*], [
coroutine_type=amd64
],
@@ -2719,9 +2648,6 @@ AS_CASE([$coroutine_type], [yes|''], [
[i386-openbsd*], [
coroutine_type=x86
],
- [aarch64-openbsd*], [
- coroutine_type=arm64
- ],
[*-openbsd*], [
coroutine_type=pthread
],
@@ -2819,22 +2745,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], [
@@ -2978,7 +2888,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]),
@@ -3012,8 +2922,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
@@ -3127,10 +3051,11 @@ AC_SUBST(EXTOBJS)
[darwin*], [ : ${LDSHARED='$(CC) -dynamic -bundle'}
: ${DLDSHARED='$(CC) -dynamiclib'}
: ${LDFLAGS=""}
- : ${LIBPATHENV=DYLD_LIBRARY_PATH}
+ : ${LIBPATHENV=DYLD_FALLBACK_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
@@ -3479,6 +3404,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}'
@@ -3758,7 +3686,7 @@ AS_IF([test x"$gcov" = xyes], [
RUBY_SETJMP_TYPE
}
-[begin]_group "installation section" && {
+: "build section" && {
dnl build rdoc index if requested
RDOCTARGET=""
CAPITARGET=""
@@ -3806,19 +3734,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)
@@ -3864,8 +3793,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]
@@ -3877,6 +3806,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])
)
@@ -3893,7 +3825,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
@@ -3917,9 +3848,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
@@ -3929,53 +3858,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 RJIT supports only x86_64 platforms, but allows arm64/aarch64 for custom JITs.
-RJIT_TARGET_OK=no
-AS_IF([test "$cross_compiling" = no],
- AS_CASE(["$target_cpu-$target_os"],
- [*android*], [
- RJIT_TARGET_OK=no
- ],
- [arm64-darwin*|aarch64-darwin*|x86_64-darwin*], [
- RJIT_TARGET_OK=yes
- ],
- [arm64-*linux*|aarch64-*linux*|x86_64-*linux*], [
- RJIT_TARGET_OK=yes
- ],
- [arm64-*bsd*|aarch64-*bsd*|x86_64-*bsd*], [
- RJIT_TARGET_OK=yes
- ]
- )
-)
-
-dnl Build RJIT on supported 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(["$RJIT_TARGET_OK"],
- [yes], [RJIT_SUPPORT=yes],
- [RJIT_SUPPORT=no]
- )]
-)
-
-AS_CASE(["$RJIT_SUPPORT"],
-[yes|dev], [
- AS_CASE(["$RJIT_SUPPORT"],
- [dev], [
- # 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 |
@@ -3986,23 +3879,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]),
@@ -4180,9 +4056,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
@@ -4248,7 +4123,6 @@ AC_SUBST(MINIOBJS)
AC_SUBST(THREAD_MODEL)
AC_SUBST(COROUTINE_TYPE, ${coroutine_type})
AC_SUBST(PLATFORM_DIR)
-AC_SUBST(USE_LLVM_WINDRES)
firstmf=`echo $FIRSTMAKEFILE | sed 's/:.*//'`
firsttmpl=`echo $FIRSTMAKEFILE | sed 's/.*://'`
@@ -4400,10 +4274,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
@@ -4508,7 +4378,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' |
(
@@ -4626,6 +4496,7 @@ AC_SUBST(DESTDIR)
AC_OUTPUT
}
+}
AS_IF([test "$silent" = yes], [], [
AS_IF([${FOLD+:} false], [], [
@@ -4673,8 +4544,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 55040d3d38..a1cb1c8ba0 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,20 +266,12 @@ 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;
};
static struct fiber_pool shared_fiber_pool = {NULL, NULL, 0, 0, 0, 0};
-void
-rb_free_shared_fiber_pool(void)
-{
- xfree(shared_fiber_pool.allocations);
-}
-
static ID fiber_initialize_keywords[3] = {0};
/*
@@ -701,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
@@ -717,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.
@@ -1066,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");
@@ -1269,8 +1255,6 @@ jit_cont_new(rb_execution_context_t *ec)
static void
jit_cont_free(struct rb_jit_cont *cont)
{
- if (!cont) return;
-
rb_native_mutex_lock(&jit_cont_lock);
if (cont == first_jit_cont) {
first_jit_cont = cont->next;
@@ -1296,42 +1280,26 @@ rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data)
if (cont->ec->vm_stack == NULL)
continue;
- const rb_control_frame_t *cfp = cont->ec->cfp;
- while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(cont->ec, cfp)) {
- if (cfp->pc && cfp->iseq && imemo_type((VALUE)cfp->iseq) == imemo_iseq) {
- callback(cfp->iseq, data);
+ const rb_control_frame_t *cfp;
+ for (cfp = RUBY_VM_END_CONTROL_FRAME(cont->ec) - 1; ; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
+ const rb_iseq_t *iseq;
+ if (cfp->pc && (iseq = cfp->iseq) != NULL && imemo_type((VALUE)iseq) == imemo_iseq) {
+ callback(iseq, data);
}
- cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
- }
- }
-}
-#if USE_YJIT
-// Update the jit_return of all CFPs to leave_exit unless it's leave_exception or not set.
-// This prevents jit_exec_exception from jumping to the caller after invalidation.
-void
-rb_yjit_cancel_jit_return(void *leave_exit, void *leave_exception)
-{
- struct rb_jit_cont *cont;
- for (cont = first_jit_cont; cont != NULL; cont = cont->next) {
- if (cont->ec->vm_stack == NULL)
- continue;
-
- const rb_control_frame_t *cfp = cont->ec->cfp;
- while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(cont->ec, cfp)) {
- if (cfp->jit_return && cfp->jit_return != leave_exception) {
- ((rb_control_frame_t *)cfp)->jit_return = leave_exit;
- }
- cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ if (cfp == cont->ec->cfp)
+ break; // reached the most recent cfp
}
}
}
-#endif
// Finish working with jit_cont.
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;
@@ -1344,8 +1312,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 *
@@ -1392,11 +1361,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
@@ -2021,7 +1994,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;
@@ -2087,10 +2059,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);
}
@@ -2117,21 +2089,13 @@ 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
fiber_storage_validate_each(VALUE key, VALUE value, VALUE _argument)
{
- Check_Type(key, T_SYMBOL);
+ rb_check_id(&key);
return ST_CONTINUE;
}
@@ -2203,9 +2167,11 @@ rb_fiber_storage_set(VALUE self, VALUE value)
static VALUE
rb_fiber_storage_aref(VALUE class, VALUE key)
{
- Check_Type(key, T_SYMBOL);
+ ID id = rb_check_id(&key);
+ if (!id) return Qnil;
+
+ VALUE storage = fiber_storage_get(fiber_current());
- VALUE storage = fiber_storage_get(fiber_current(), FALSE);
if (storage == Qnil) return Qnil;
return rb_hash_aref(storage, key);
@@ -2224,17 +2190,12 @@ rb_fiber_storage_aref(VALUE class, VALUE key)
static VALUE
rb_fiber_storage_aset(VALUE class, VALUE key, VALUE value)
{
- Check_Type(key, T_SYMBOL);
+ ID id = rb_check_id(&key);
+ if (!id) return Qnil;
- 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
@@ -2378,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), 0, storage);
+ return fiber_initialize(fiber_alloc(rb_cFiber), rb_proc_new(func, obj), rb_fiber_pool_default(Qnil), 1, storage);
}
VALUE
@@ -2512,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));
@@ -2537,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;
@@ -2546,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);
@@ -2574,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);
}
@@ -2587,12 +2548,12 @@ rb_threadptr_root_fiber_release(rb_thread_t *th)
/* ignore. A root fiber object will free th->ec */
}
else {
- rb_execution_context_t *ec = rb_current_execution_context(false);
+ rb_execution_context_t *ec = GET_EC();
VM_ASSERT(th->ec->fiber_ptr->cont.type == FIBER_CONTEXT);
VM_ASSERT(th->ec->fiber_ptr->cont.self == 0);
- if (ec && th->ec == ec) {
+ if (th->ec == ec) {
rb_ractor_set_current_ec(th->ractor, NULL);
}
fiber_free(th->ec->fiber_ptr);
@@ -2673,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)
{
@@ -2774,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;
}
@@ -2817,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;
@@ -2860,8 +2799,7 @@ rb_fiber_blocking(VALUE class)
// If we are already blocking, this is essentially a no-op:
if (fiber->blocking) {
return rb_yield(fiber_value);
- }
- else {
+ } else {
return rb_ensure(fiber_blocking_yield, fiber_value, fiber_blocking_ensure, fiber_value);
}
}
@@ -3221,13 +3159,12 @@ 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 == fiber_current()) {
- rb_exc_raise(exception);
- }
- else if (fiber->resuming_fiber) {
- return fiber_raise(fiber->resuming_fiber, exception);
+ 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);
@@ -3240,9 +3177,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);
}
/*
@@ -3265,8 +3200,6 @@ rb_fiber_raise(VALUE fiber, int argc, const VALUE *argv)
* the exception, and the third parameter is an array of callback information.
* Exceptions are caught by the +rescue+ clause of <code>begin...end</code>
* blocks.
- *
- * Raises +FiberError+ if called on a Fiber belonging to another +Thread+.
*/
static VALUE
rb_fiber_m_raise(int argc, VALUE *argv, VALUE self)
@@ -3276,45 +3209,6 @@ rb_fiber_m_raise(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * fiber.kill -> nil
- *
- * Terminates the fiber by raising an uncatchable exception.
- * It only terminates the given fiber and no other fiber, returning +nil+ to
- * another fiber if that fiber was calling #resume or #transfer.
- *
- * <tt>Fiber#kill</tt> only interrupts another fiber when it is in Fiber.yield.
- * If called on the current fiber then it raises that exception at the <tt>Fiber#kill</tt> call site.
- *
- * If the fiber has not been started, transition directly to the terminated state.
- *
- * If the fiber is already terminated, does nothing.
- *
- * Raises FiberError if called on a fiber belonging to another thread.
- */
-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
@@ -3471,15 +3365,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);
@@ -3497,7 +3382,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/arm64/Context.S b/coroutine/arm64/Context.S
index eeb0f774a3..07d50d30df 100644
--- a/coroutine/arm64/Context.S
+++ b/coroutine/arm64/Context.S
@@ -18,25 +18,11 @@
.align 2
#endif
-## NOTE(PAC): Use we HINT mnemonics instead of PAC mnemonics to
-## keep compatibility with those assemblers that don't support PAC.
-##
-## See "Providing protection for complex software" for more details about PAC/BTI
-## https://developer.arm.com/architectures/learn-the-architecture/providing-protection-for-complex-software
-
.global PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer)
PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
-#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT != 0)
- # paciasp (it also acts as BTI landing pad, so no need to insert BTI also)
- hint #25
-#elif defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT != 0)
- # For the the case PAC is not enabled but BTI is.
- # bti c
- hint #34
-#endif
# Make space on the stack for caller registers
- sub sp, sp, 0xa0
+ sub sp, sp, 0xb0
# Save caller registers
stp d8, d9, [sp, 0x00]
@@ -50,6 +36,9 @@ PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
stp x27, x28, [sp, 0x80]
stp x29, x30, [sp, 0x90]
+ # Save return address
+ str x30, [sp, 0xa0]
+
# Save stack pointer to x0 (first argument)
mov x2, sp
str x2, [x0, 0]
@@ -70,51 +59,15 @@ PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
ldp x27, x28, [sp, 0x80]
ldp x29, x30, [sp, 0x90]
- # Pop stack frame
- add sp, sp, 0xa0
+ # Load return address into x4
+ ldr x4, [sp, 0xa0]
-#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT != 0)
- # autiasp: Authenticate x30 (LR) with SP and key A
- hint #29
-#endif
+ # Pop stack frame
+ add sp, sp, 0xb0
- # Jump to return address (in x30)
- ret
+ # Jump to return address (in x4)
+ ret x4
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
-
-#if __ARM_FEATURE_BTI_DEFAULT != 0 || __ARM_FEATURE_PAC_DEFAULT != 0
-/* See "ELF for the Arm 64-bit Architecture (AArch64)"
- https://github.com/ARM-software/abi-aa/blob/2023Q3/aaelf64/aaelf64.rst#program-property */
-# define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1<<0)
-# define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1<<1)
-
-# if __ARM_FEATURE_BTI_DEFAULT != 0
-# define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
-# else
-# define BTI_FLAG 0
-# endif
-# if __ARM_FEATURE_PAC_DEFAULT != 0
-# define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
-# else
-# define PAC_FLAG 0
-# endif
-
- # The note section format is described by Note Section in Chapter 5
- # of "System V Application Binary Interface, Edition 4.1".
- .pushsection .note.gnu.property, "a"
- .p2align 3
- .long 0x4 /* Name size ("GNU\0") */
- .long 0x10 /* Descriptor size */
- .long 0x5 /* Type: NT_GNU_PROPERTY_TYPE_0 */
- .asciz "GNU" /* Name */
- # Begin descriptor
- .long 0xc0000000 /* Property type: GNU_PROPERTY_AARCH64_FEATURE_1_AND */
- .long 0x4 /* Property size */
- .long (BTI_FLAG|PAC_FLAG)
- .long 0x0 /* 8-byte alignment padding */
- # End descriptor
- .popsection
-#endif
diff --git a/coroutine/arm64/Context.h b/coroutine/arm64/Context.h
index 1819fa5be9..1472621f48 100644
--- a/coroutine/arm64/Context.h
+++ b/coroutine/arm64/Context.h
@@ -17,7 +17,7 @@
#define COROUTINE __attribute__((noreturn)) void
-enum {COROUTINE_REGISTERS = 0xa0 / 8};
+enum {COROUTINE_REGISTERS = 0xb0 / 8};
#if defined(__SANITIZE_ADDRESS__)
#define COROUTINE_SANITIZE_ADDRESS
@@ -50,23 +50,6 @@ static inline void coroutine_initialize_main(struct coroutine_context * context)
context->stack_pointer = NULL;
}
-#if defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT != 0
-// Sign the given instruction address with the given modifier and key A
-static inline void *ptrauth_sign_instruction_addr(void *addr, void *modifier) {
- register void *r17 __asm("r17") = addr;
- register void *r16 __asm("r16") = modifier;
- // Use HINT mnemonic instead of PACIA1716 for compatibility with older assemblers.
- asm ("hint #8;" : "+r"(r17) : "r"(r16));
- addr = r17;
- return addr;
-}
-#else
-// No-op if PAC is not enabled
-static inline void *ptrauth_sign_instruction_addr(void *addr, void *modifier) {
- return addr;
-}
-#endif
-
static inline void coroutine_initialize(
struct coroutine_context *context,
coroutine_start start,
@@ -83,13 +66,12 @@ static inline void coroutine_initialize(
// Stack grows down. Force 16-byte alignment.
char * top = (char*)stack + size;
- top = (char *)((uintptr_t)top & ~0xF);
- context->stack_pointer = (void**)top;
+ 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[0x98 / 8] = ptrauth_sign_instruction_addr((void*)start, (void*)top);
+ context->stack_pointer[0xa0 / 8] = (void*)start;
}
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
diff --git a/coroutine/asyncify/Context.h b/coroutine/asyncify/Context.h
index 71791a4004..7dba829a1d 100644
--- a/coroutine/asyncify/Context.h
+++ b/coroutine/asyncify/Context.h
@@ -13,7 +13,6 @@
#include <stddef.h>
#include <stdio.h>
-#include <stdint.h>
#include "wasm/asyncify.h"
#include "wasm/machine.h"
#include "wasm/fiber.h"
@@ -48,13 +47,10 @@ 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)
{
- // 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);
+ if (ASYNCIFY_CORO_DEBUG) fprintf(stderr, "[%s] entry (context = %p, stack = %p ... %p)\n", __func__, context, stack, (char *)stack + size);
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 *)sp;
+ context->current_sp = (char *)stack + size;
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 7bcf1ada30..43e92a27f0 100644
--- a/cygwin/GNUmakefile.in
+++ b/cygwin/GNUmakefile.in
@@ -2,18 +2,10 @@ 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)"
-ifeq (@USE_LLVM_WINDRES@,yes) # USE_LLVM_WINDRES
- # llvm-windres fails when preprocessor options are added
- windres-cpp :=
-else
- windres-cpp := $(CPP) -xc
- windres-cpp := --preprocessor=$(firstword $(windres-cpp)) \
- $(addprefix --preprocessor-arg=,$(wordlist 2,$(words $(windres-cpp)),$(windres-cpp)))
-endif
+windres-cpp := $(CPP) -xc
+windres-cpp := --preprocessor=$(firstword $(windres-cpp)) \
+ $(addprefix --preprocessor-arg=,$(wordlist 2,$(words $(windres-cpp)),$(windres-cpp)))
WINDRES = @WINDRES@ $(windres-cpp) -DRC_INVOKED
STRIP = @STRIP@
@@ -49,7 +41,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)
@@ -72,7 +63,7 @@ $(PROGRAM): $(RUBY_INSTALL_NAME).res.$(OBJEXT)
$(WPROGRAM): $(RUBYW_INSTALL_NAME).res.$(OBJEXT)
@rm -f $@
$(ECHO) linking $@
- $(Q) $(PURIFY) $(CC) $(MUNICODE_FLAG) -mwindows -e $(SYMBOL_PREFIX)mainCRTStartup $(LDFLAGS) $(XLDFLAGS) \
+ $(Q) $(PURIFY) $(CC) -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 96c1a455b3..3f73f83fc5 100644
--- a/dir.c
+++ b/dir.c
@@ -466,26 +466,31 @@ 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;
if (dir->dir) closedir(dir->dir);
+ xfree(dir);
}
-RUBY_REFERENCES(dir_refs) = {
- RUBY_REF_EDGE(struct dir_data, path),
- RUBY_REF_END
-};
+static size_t
+dir_memsize(const void *ptr)
+{
+ return sizeof(struct dir_data);
+}
static const rb_data_type_t dir_data_type = {
"dir",
- {
- RUBY_REFS_LIST_PTR(dir_refs),
- dir_free,
- NULL, // Nothing allocated externally, so don't need a memsize function
- },
- 0, NULL, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
+ {dir_mark, dir_free, dir_memsize,},
+ 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE dir_close(VALUE);
@@ -586,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
@@ -652,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)
@@ -692,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)
@@ -722,14 +685,14 @@ dir_fileno(VALUE dir)
#endif
/*
- * call-seq:
- * path -> string or nil
+ * call-seq:
+ * dir.path -> string or nil
+ * dir.to_path -> string or nil
*
- * Returns the +dirpath+ string that was used to create +self+
- * (or +nil+ if created by method Dir.for_fd):
- *
- * 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)
@@ -783,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)
@@ -803,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);
}
@@ -823,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)
@@ -882,17 +844,16 @@ dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE), VALUE arg, int children_o
#ifdef HAVE_TELLDIR
/*
- * call-seq:
- * tell -> integer
+ * call-seq:
+ * dir.pos -> integer
+ * dir.tell -> integer
*
- * Returns the current position of +self+;
- * see {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like]:
- *
- * 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)
@@ -910,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)
@@ -945,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)
@@ -975,19 +923,15 @@ dir_set_pos(VALUE dir, VALUE pos)
#endif
/*
- * call-seq:
- * rewind -> self
- *
- * Sets the position in +self+ to zero;
- * see {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like]:
+ * call-seq:
+ * dir.rewind -> dir
*
- * 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)
@@ -1000,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)
@@ -1035,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);
@@ -1047,19 +987,18 @@ static VALUE chdir_thread = Qnil;
struct chdir_data {
VALUE old_path, new_path;
int done;
- bool yield_path;
};
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))
chdir_thread = rb_thread_current();
- return args->yield_path ? rb_yield(args->new_path) : rb_yield_values2(0, NULL);
+ return rb_yield(args->new_path);
}
static VALUE
@@ -1070,103 +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;
}
-static VALUE
-chdir_path(VALUE path, bool yield_path)
-{
- 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 chdir_data args;
-
- args.old_path = rb_str_encode_ospath(rb_dir_getwd());
- args.new_path = path;
- args.done = FALSE;
- args.yield_path = yield_path;
- return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
- }
- else {
- char *p = RSTRING_PTR(path);
- int r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_chdir, p,
- RUBY_UBF_IO, 0);
- if (r < 0)
- rb_sys_fail_path(path);
- }
-
- return INT2FIX(0);
-}
-
/*
- * 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 (yielding the new path).
- * - 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)
@@ -1185,114 +1071,6 @@ dir_s_chdir(int argc, VALUE *argv, VALUE obj)
path = rb_str_new2(dist);
}
- return chdir_path(path, true);
-}
-
-#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)
- * Dir.pwd # => "/usr"
- *
- * With a block, temporarily changes the working directory:
- *
- * - Calls the block with the argument.
- * - Changes to the given directory.
- * - Executes the block (yields no args).
- * - Restores the previous working directory.
- * - Returns the block's return value.
- *
- * Example:
- *
- * Dir.chdir('/var/spool/mail')
- * Dir.pwd # => "/var/spool/mail"
- * dir = Dir.new('/tmp')
- * fd = dir.fileno
- * Dir.fchdir(fd) 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");
@@ -1301,58 +1079,23 @@ dir_s_fchdir(VALUE klass, VALUE fd_value)
}
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;
+ struct chdir_data args;
+
+ args.old_path = rb_str_encode_ospath(rb_dir_getwd());
+ args.new_path = path;
args.done = FALSE;
- return rb_ensure(fchdir_yield, (VALUE)&args, fchdir_restore, (VALUE)&args);
+ return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
}
else {
- int r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_fchdir, &fd,
- RUBY_UBF_IO, 0);
+ char *p = RSTRING_PTR(path);
+ int r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_chdir, p,
+ RUBY_UBF_IO, 0);
if (r < 0)
- rb_sys_fail("fchdir");
+ rb_sys_fail_path(path);
}
return INT2FIX(0);
}
-#else
-#define dir_s_fchdir rb_f_notimplement
-#endif
-
-/*
- * call-seq:
- * chdir -> 0
- * chdir { ... } -> object
- *
- * Changes the current working directory to +self+:
- *
- * Dir.pwd # => "/"
- * dir = Dir.new('example')
- * dir.chdir
- * Dir.pwd # => "/example"
- *
- * With a block, temporarily changes the working directory:
- *
- * - Calls the block.
- * - Changes to the given directory.
- * - Executes the block (yields no args).
- * - Restores the previous working directory.
- * - Returns the block's return value.
- *
- * Uses Dir.fchdir if available, and Dir.chdir if not, see those
- * methods for caveats.
- */
-static VALUE
-dir_chdir(VALUE dir)
-{
-#if defined(HAVE_FCHDIR) && defined(HAVE_DIRFD) && HAVE_FCHDIR && HAVE_DIRFD
- return dir_s_fchdir(rb_cDir, dir_fileno(dir));
-#else
- return chdir_path(dir_get(dir)->path, false);
-#endif
-}
#ifndef _WIN32
VALUE
@@ -1400,14 +1143,16 @@ rb_dir_getwd(void)
}
/*
- * call-seq:
- * Dir.pwd -> string
- *
- * Returns the path to the current working directory:
+ * call-seq:
+ * Dir.getwd -> string
+ * Dir.pwd -> string
*
- * 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)
@@ -1437,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.
- *
- * Only a privileged process may call +chroot+.
+ * call-seq:
+ * Dir.chroot( string ) -> 0
*
- * 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)
@@ -1475,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)
@@ -1522,14 +1262,13 @@ nogvl_rmdir(void *ptr)
}
/*
- * call-seq:
- * Dir.rmdir(dirpath) -> 0
- *
- * Removes the directory at +dirpath+ from the underlying file system:
+ * call-seq:
+ * Dir.delete( string ) -> 0
+ * Dir.rmdir( string ) -> 0
+ * Dir.unlink( string ) -> 0
*
- * Dir.rmdir('foo') # => 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)
@@ -1737,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 */
@@ -3130,7 +2869,7 @@ push_glob(VALUE ary, VALUE str, VALUE base, int flags)
fd = AT_FDCWD;
if (!NIL_P(base)) {
if (!RB_TYPE_P(base, T_STRING) || !rb_enc_check(str, base)) {
- struct dir_data *dirp = RTYPEDDATA_GET_DATA(base);
+ struct dir_data *dirp = DATA_PTR(base);
if (!dirp->dir) dir_closed();
#ifdef HAVE_DIRFD
if ((fd = dirfd(dirp->dir)) == -1)
@@ -3254,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+:
- *
- * Dir.foreach('/example') {|entry_name| p entry_name }
- *
- * Output:
+ * 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
*
- * "config.h"
- * "lib"
- * "main.rb"
- * ".."
- * "."
+ * Calls the block once for each entry in the named directory, passing
+ * the filename of each entry as a parameter to the block.
*
- * Encoding:
+ * If no block is given, an enumerator is returned instead.
*
- * Dir.foreach('/example') {|entry_name| p entry_name.encoding; break }
- * Dir.foreach('/example', encoding: 'US-ASCII') {|entry_name| p entry_name.encoding; break }
+ * Dir.foreach("testdir") {|x| puts "Got #{x}" }
*
- * Output:
+ * <em>produces:</em>
*
- * #<Encoding:UTF-8>
- * #<Encoding:US-ASCII>
+ * Got .
+ * Got ..
+ * Got config.h
+ * Got main.rb
*
- * 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)
@@ -3304,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)
@@ -3336,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)
@@ -3355,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 once for each entry except for "." and ".." in
+ * this directory, passing the filename of each entry as a parameter
+ * to the block.
*
- * Calls the block with each entry name in +self+
- * except <tt>'.'</tt> and <tt>'..'</tt>:
+ * If no block is given, an enumerator is returned instead.
*
- * dir = Dir.new('/example')
- * dir.each_child {|entry_name| p entry_name }
+ * d = Dir.new("testdir")
+ * d.each_child {|x| puts "Got #{x}" }
*
- * Output:
+ * <em>produces:</em>
*
- * "config.h"
- * "lib"
- * "main.rb"
+ * Got config.h
+ * Got main.rb
*
- * If no block is given, returns an enumerator.
*/
static VALUE
dir_each_child_m(VALUE dir)
@@ -3380,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
@@ -3399,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)
@@ -3489,16 +3228,12 @@ file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
}
/*
- * call-seq:
- * Dir.home(user_name = nil) -> dirpath
+ * call-seq:
+ * Dir.home() -> "/home/me"
+ * Dir.home("root") -> "/root"
*
- * Retruns the home directory path of the user specified with +user_name+
- * if it is not +nil+, or the current login user:
- *
- * 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)
@@ -3523,15 +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?(file_name) -> true or false
*
- * Dir.exist?('/example') # => true
- * Dir.exist?('/nosuch') # => false
- * Dir.exist?('/example/main.rb') # => false
- *
- * Same as File.directory?.
+ * Returns <code>true</code> if the named file is a directory,
+ * <code>false</code> otherwise.
*
*/
VALUE
@@ -3558,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) {
@@ -3573,18 +3304,10 @@ nogvl_dir_empty_p(void *ptr)
/*
* call-seq:
- * Dir.empty?(dirpath) -> true or false
- *
- * Returns whether +dirpath+ specifies an empty directory:
- *
- * dirpath = '/tmp/foo'
- * Dir.mkdir(dirpath)
- * Dir.empty?(dirpath) # => true
- * Dir.empty?('/example') # => false
- * Dir.empty?('/example/main.rb') # => false
+ * Dir.empty?(path_name) -> true or 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)
@@ -3620,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;
}
@@ -3634,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);
@@ -3654,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);
@@ -3673,26 +3393,51 @@ 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: FNM_NOESCAPE
- * {File::FNM_NOESCAPE}[rdoc-ref:File::Constants@File-3A-3AFNM_NOESCAPE] */
+ /* 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: FNM_PATHNAME
- * {File::FNM_PATHNAME}[rdoc-ref:File::Constants@File-3A-3AFNM_PATHNAME] */
+
+ /* 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: FNM_DOTMATCH
- * {File::FNM_DOTMATCH}[rdoc-ref:File::Constants@File-3A-3AFNM_DOTMATCH] */
+
+ /* 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: FNM_CASEFOLD
- * {File::FNM_CASEFOLD}[rdoc-ref:File::Constants@File-3A-3AFNM_CASEFOLD] */
+
+ /* 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: FNM_EXTGLOB
- * {File::FNM_EXTGLOB}[rdoc-ref:File::Constants@File-3A-3AFNM_EXTGLOB] */
+
+ /* 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: FNM_SYSCASE
- * {File::FNM_SYSCASE}[rdoc-ref:File::Constants@File-3A-3AFNM_SYSCASE] */
+
+ /* 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: FNM_SHORTNAME
- * {File::FNM_SHORTNAME}[rdoc-ref:File::Constants@File-3A-3AFNM_SHORTNAME] */
+
+ /* 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 632c49eee9..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@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@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 b4c2fb9423..0edd709bbe 100644
--- a/dln.c
+++ b/dln.c
@@ -272,15 +272,13 @@ rb_w32_check_imported(HMODULE ext, HMODULE mine)
static bool
dln_incompatible_func(void *handle, const char *funcname, void *const fp, const char **libname)
{
+ Dl_info dli;
void *ex = dlsym(handle, funcname);
if (!ex) return false;
if (ex == fp) return false;
-# if defined(HAVE_DLADDR)
- Dl_info dli;
if (dladdr(ex, &dli)) {
*libname = dli.dli_fname;
}
-# endif
return true;
}
@@ -394,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);
@@ -421,63 +413,33 @@ dln_open(const char *file)
static void *
dln_sym(void *handle, const char *symbol)
{
-#if defined(_WIN32)
- return GetProcAddress(handle, symbol);
-#elif defined(USE_DLN_DLOPEN)
- return dlsym(handle, symbol);
-#endif
-}
+ void *func;
+ const char *error;
-static void *
-dln_sym_func(void *handle, const char *symbol)
-{
- void *func = dln_sym(handle, symbol);
+#if defined(_WIN32)
+ char message[1024];
+ func = GetProcAddress(handle, symbol);
if (func == NULL) {
- const char *error;
-#if defined(_WIN32)
- char message[1024];
error = dln_strerror();
+ goto failed;
+ }
+
#elif defined(USE_DLN_DLOPEN)
+ func = dlsym(handle, symbol);
+ if (func == NULL) {
const size_t errlen = strlen(error = dln_strerror()) + 1;
error = memcpy(ALLOCA_N(char, errlen), error, errlen);
-#endif
- dln_loaderror("%s - %s", error, symbol);
+ goto failed;
}
- return func;
-}
-
-#define dln_sym_callable(rettype, argtype, handle, symbol) \
- (*(rettype (*)argtype)dln_sym_func(handle, symbol))
#endif
-void *
-dln_symbol(void *handle, const char *symbol)
-{
-#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
- if (EXTERNAL_PREFIX[0]) {
- const size_t symlen = strlen(symbol);
- char *const tmp = ALLOCA_N(char, symlen + sizeof(EXTERNAL_PREFIX));
- if (!tmp) dln_memerror();
- memcpy(tmp, EXTERNAL_PREFIX, sizeof(EXTERNAL_PREFIX) - 1);
- memcpy(tmp + sizeof(EXTERNAL_PREFIX) - 1, symbol, symlen + 1);
- symbol = tmp;
- }
- if (handle == NULL) {
-# if defined(USE_DLN_DLOPEN)
- handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
-# elif defined(_WIN32)
- handle = rb_libruby_handle();
-# else
- return NULL;
-# endif
- }
- return dln_sym(handle, symbol);
-#else
- return NULL;
-#endif
-}
+ return func;
+ failed:
+ dln_loaderror("%s - %s", error, symbol);
+}
+#endif
#if defined(RUBY_DLN_CHECK_ABI) && defined(USE_DLN_DLOPEN)
static bool
@@ -495,9 +457,8 @@ dln_load(const char *file)
void *handle = dln_open(file);
#ifdef RUBY_DLN_CHECK_ABI
- typedef unsigned long long abi_version_number;
- abi_version_number binary_abi_version =
- dln_sym_callable(abi_version_number, (void), handle, EXTERNAL_PREFIX "ruby_abi_version")();
+ unsigned long long (*abi_version_fct)(void) = (unsigned long long(*)(void))dln_sym(handle, "ruby_abi_version");
+ unsigned long long binary_abi_version = (*abi_version_fct)();
if (binary_abi_version != ruby_abi_version() && abi_check_enabled_p()) {
dln_loaderror("incompatible ABI version of binary - %s", file);
}
@@ -505,9 +466,10 @@ dln_load(const char *file)
char *init_fct_name;
init_funcname(&init_fct_name, file);
+ void (*init_fct)(void) = (void(*)(void))dln_sym(handle, init_fct_name);
/* Call the init code */
- dln_sym_callable(void, (void), handle, init_fct_name)();
+ (*init_fct)();
return handle;
diff --git a/dln.h b/dln.h
index d624bb6611..902f753450 100644
--- a/dln.h
+++ b/dln.h
@@ -25,7 +25,6 @@ RUBY_SYMBOL_EXPORT_BEGIN
char *dln_find_exe_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
char *dln_find_file_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
void *dln_load(const char*);
-void *dln_symbol(void*,const char*);
RUBY_SYMBOL_EXPORT_END
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/dmydln.c b/dmydln.c
index b1516937d3..d05cda0b8e 100644
--- a/dmydln.c
+++ b/dmydln.c
@@ -8,12 +8,3 @@ dln_load(const char *file)
UNREACHABLE_RETURN(NULL);
}
-
-NORETURN(void *dln_symbol(void*,const char*));
-void*
-dln_symbol(void *handle, const char *symbol)
-{
- rb_loaderror("this executable file can't load extension libraries");
-
- UNREACHABLE_RETURN(NULL);
-}
diff --git a/doc/.document b/doc/.document
index 5a58e6e3ad..5ef2d99651 100644
--- a/doc/.document
+++ b/doc/.document
@@ -1,11 +1,8 @@
*.md
*.rb
-[^_]*.rdoc
+*.rdoc
contributing
NEWS
syntax
optparse
rdoc
-regexp
-rjit
-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/_regexp.rdoc b/doc/_regexp.rdoc
deleted file mode 100644
index 7b71eee984..0000000000
--- a/doc/_regexp.rdoc
+++ /dev/null
@@ -1,1276 +0,0 @@
-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_).
-
-A common notation for a regexp uses enclosing slash characters:
-
- /foo/
-
-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>:
-
- 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.
-
-== \Regexp Uses
-
-A regexp may be used:
-
-- To extract substrings based on a given pattern:
-
- re = /foo/ # => /foo/
- re.match('food') # => #<MatchData "foo">
- re.match('good') # => nil
-
- See sections {Method match}[rdoc-ref:Regexp@Method+match]
- and {Operator =~}[rdoc-ref:Regexp@Operator+-3D~].
-
-- To determine whether a string matches a given pattern:
-
- re.match?('food') # => true
- re.match?('good') # => false
-
- See section {Method match?}[rdoc-ref:Regexp@Method+match-3F].
-
-- 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.
-
- See {Regexp Methods}[rdoc-ref:regexp/methods.rdoc].
-
-== \Regexp Objects
-
-A regexp object has:
-
-- A source; see {Sources}[rdoc-ref:Regexp@Sources].
-
-- Several modes; see {Modes}[rdoc-ref:Regexp@Modes].
-
-- A timeout; see {Timeouts}[rdoc-ref:Regexp@Timeouts].
-
-- An encoding; see {Encodings}[rdoc-ref:Regexp@Encodings].
-
-== Creating a \Regexp
-
-A regular expression may be created with:
-
-- A regexp literal using slash characters
- (see {Regexp Literals}[rdoc-ref:syntax/literals.rdoc@Regexp+Literals]):
-
- # This is a very common usage.
- /foo/ # => /foo/
-
-- A <tt>%r</tt> regexp literal
- (see {%r: Regexp Literals}[rdoc-ref:syntax/literals.rdoc@25r-3A+Regexp+Literals]):
-
- # 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/
-
- # Certain "paired" characters can be delimiters.
- %r[foo] # => /foo/
- %r{foo} # => /foo/
- %r(foo) # => /foo/
- %r<foo> # => /foo/
-
-- \Method Regexp.new.
-
-== \Method <tt>match</tt>
-
-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@Global+Variables]:
-
- 'food'.match(/foo/) # => #<MatchData "foo">
- 'food'.match(/bar/) # => nil
-
-== Operator <tt>=~</tt>
-
-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@Global+Variables]:
-
- /bar/ =~ 'foo bar' # => 4
- 'foo bar' =~ /bar/ # => 4
- /baz/ =~ 'foo bar' # => nil
-
-== \Method <tt>match?</tt>
-
-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@Global+Variables]:
-
- 'food'.match?(/foo/) # => true
- 'food'.match?(/bar/) # => false
-
-== Global Variables
-
-Certain regexp-oriented methods assign values to global variables:
-
-- <tt>#match</tt>: see {Method match}[rdoc-ref:Regexp@Method+match].
-- <tt>#=~</tt>: see {Operator =~}[rdoc-ref:Regexp@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@Special+Characters]
-- {Source literals}[rdoc-ref:Regexp@Source+Literals]
-- {Character classes}[rdoc-ref:Regexp@Character+Classes]
-- {Shorthand character classes}[rdoc-ref:Regexp@Shorthand+Character+Classes]
-- {Anchors}[rdoc-ref:Regexp@Anchors]
-- {Alternation}[rdoc-ref:Regexp@Alternation]
-- {Quantifiers}[rdoc-ref:Regexp@Quantifiers]
-- {Groups and captures}[rdoc-ref:Regexp@Groups+and+Captures]
-- {Unicode}[rdoc-ref:Regexp@Unicode]
-- {POSIX Bracket Expressions}[rdoc-ref:Regexp@POSIX+Bracket+Expressions]
-- {Comments}[rdoc-ref:Regexp@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@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))
-
-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@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:
-
- 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
-
-Adding one or more pairs of parentheses, <tt>(_subexpression_)</tt>,
-defines _groups_, which may result in multiple matched substrings,
-called _captures_:
-
- 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
-
-The first capture is the entire matched string;
-the other captures are the matched substrings from the groups.
-
-A group may have a {quantifier}[rdoc-ref:Regexp@Quantifiers]:
-
- re = /July 4(th)?/
- re.match('July 4') # => #<MatchData "July 4" 1:nil>
- re.match('July 4th') # => #<MatchData "July 4th" 1:"th">
-
- re = /(foo)*/
- re.match('') # => #<MatchData "" 1:nil>
- re.match('foo') # => #<MatchData "foo" 1:"foo">
- re.match('foofoo') # => #<MatchData "foofoo" 1:"foo">
-
- re = /(foo)+/
- re.match('') # => nil
- re.match('foo') # => #<MatchData "foo" 1:"foo">
- re.match('foofoo') # => #<MatchData "foofoo" 1:"foo">
-
-The returned \MatchData object gives access to the matched substrings:
-
- 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"
-
-==== Non-Capturing Groups
-
-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.
-
-A non-capturing group begins with <tt>?:</tt> (inside the parentheses):
-
- # 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">
-
-==== Backreferences
-
-A group match may also be referenced within the regexp itself;
-such a reference is called a +backreference+:
-
- /[csh](..) [csh]\1 in/.match('The cat sat in the hat')
- # => #<MatchData "cat sat in" 1:"at">
-
-This table shows how each subexpression in the regexp above
-matches a substring in the target string:
-
- | 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' |
-
-A regexp may contain any number of groups:
-
-- For a large number of groups:
-
- - 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_.
-
-- <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):
-
- '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
-
-A group may be made _atomic_ with <tt>(?></tt>_subexpression_<tt>)</tt>.
-
-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.
-
-In this way _subexpression_ is treated as a non-divisible whole.
-Atomic grouping is typically used to optimise patterns
-to prevent needless backtracking .
-
-Example (without atomic grouping):
-
- /".*"/.match('"Quote"') # => #<MatchData "\"Quote\"">
-
-Analysis:
-
-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.
-
-If subexpression <tt>.*</tt> is grouped atomically,
-the backtracking is disabled, and the overall match fails:
-
- /"(?>.*)"/.match('"Quote"') # => nil
-
-Atomic grouping can affect performance;
-see {Atomic Group}[https://www.regular-expressions.info/atomic.html].
-
-==== Subexpression Calls
-
-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>):
-
- /\A(?<paren>\(\g<paren>*\))*\z/.match('(())')
- # ^1
- # ^2
- # ^3
- # ^4
- # ^5
- # ^6
- # ^7
- # ^8
- # ^9
- # ^10
-
-The pattern:
-
-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.
-
-See {Subexpression calls}[https://learnbyexample.github.io/Ruby_Regexp/groupings-and-backreferences.html?highlight=subexpression#subexpression-calls].
-
-==== Conditionals
-
-The conditional construct takes the form <tt>(?(_cond_)_yes_|_no_)</tt>, where:
-
-- _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.
-
-Examples:
-
- 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
-
- 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
-
-
-==== Absence Operator
-
-The absence operator is a special group that matches anything which does _not_ match the contained subexpressions.
-
- /(?~real)/.match('surrealist') # => #<MatchData "surrea">
- /(?~real)ist/.match('surrealist') # => #<MatchData "ealist">
- /sur(?~real)ist/.match('surrealist') # => nil
-
-=== Unicode
-
-==== Unicode Properties
-
-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:
-
- /\p{Alpha}/.match('a') # => #<MatchData "a">
- /\p{Alpha}/.match('1') # => nil
-
-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
-
-Or by using <tt>\P</tt> (uppercase +P+):
-
- /\P{Alpha}/.match('1') # => #<MatchData "1">
- /\P{Alpha}/.match('a') # => nil
-
-See {Unicode Properties}[rdoc-ref:regexp/unicode_properties.rdoc]
-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
- 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,
- 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 in one of these Unicode character
- categories (see below) or having one of these Unicode properties:
-
- - Unicode categories:
- - +Mark+ (+M+).
- - <tt>Decimal Number</tt> (+Nd+)
- - <tt>Connector Punctuation</tt> (+Pc+).
-
- - Unicode properties:
- - +Alpha+
- - <tt>Join_Control</tt>
-
-- <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 or having one of these Unicode properties:
-
- - Unicode categories:
- - +Mark+ (+M+).
- - <tt>Decimal Number</tt> (+Nd+)
- - <tt>Connector Punctuation</tt> (+Pc+).
-
- - Unicode properties:
- - +Alpha+
- - <tt>Join_Control</tt>
-
-=== 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@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@Case-Insensitive+Mode].
-- +m+: <tt>/_pattern_/m</tt> sets
- {Multiline Mode}[rdoc-ref:Regexp@Multiline+Mode].
-- +x+: <tt>/_pattern_/x</tt> sets
- {Extended Mode}[rdoc-ref:Regexp@Extended+Mode].
-- +o+: <tt>/_pattern_/o</tt> sets
- {Interpolation Mode}[rdoc-ref:Regexp@Interpolation+Mode].
-
-Any, all, or none of these may be applied.
-
-Modifiers +i+, +m+, and +x+ may be applied to subexpressions:
-
-- <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
-
-Example:
-
- 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
-
-\Method Regexp#options returns an integer whose value showing
-the settings for case-insensitivity mode, multiline mode, and extended mode.
-
-=== Case-Insensitive Mode
-
-By default, a regexp is case-sensitive:
-
- /foo/.match('FOO') # => nil
-
-Modifier +i+ enables case-insensitive mode:
-
- /foo/i.match('FOO')
- # => #<MatchData "FOO">
-
-\Method Regexp#casefold? returns whether the mode is case-insensitive.
-
-=== Multiline Mode
-
-The multiline-mode in Ruby is what is commonly called a "dot-all mode":
-
-- Without the +m+ modifier, the subexpression <tt>.</tt> does not match newlines:
-
- /a.c/.match("a\nc") # => nil
-
-- With the modifier, it does match:
-
- /a.c/m.match("a\nc") # => #<MatchData "a\nc">
-
-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.
-
-=== Extended Mode
-
-Modifier +x+ enables extended mode, which means that:
-
-- 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.
-
-In extended mode, whitespace and comments may be used
-to form a self-documented regexp.
-
-Regexp not in extended mode (matches some Roman numerals):
-
- 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">
-
-Regexp in extended mode:
-
- 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">
-
-=== Interpolation Mode
-
-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.
-
-Without modifier +o+:
-
- 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
-
-With modifier +o+:
-
- start = Time.now
- words.each {|word| word.match(/\A[#{letters}]+\z/o) }
- Time.now - start # => 5.0010866
-
-Note that if the literal regexp does not have interpolations,
-the +o+ behavior is the default.
-
-== Encodings
-
-By default, a regexp with only US-ASCII characters has US-ASCII encoding:
-
- re = /foo/
- re.source.encoding # => #<Encoding:US-ASCII>
- re.encoding # => #<Encoding:US-ASCII>
-
-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.
-
-- <tt>/_pat_/n</tt>: US-ASCII if only containing US-ASCII characters,
- otherwise ASCII-8BIT:
-
- /foo/n.encoding # => #<Encoding:US-ASCII>
- /foo\xff/n.encoding # => #<Encoding:ASCII-8BIT>
- /foo\x7f/n.encoding # => #<Encoding:US-ASCII>
-
-- <tt>/_pat_/u</tt>: UTF-8
-
- /foo/u.encoding # => #<Encoding:UTF-8>
-
-- <tt>/_pat_/e</tt>: EUC-JP
-
- /foo/e.encoding # => #<Encoding:EUC-JP>
-
-- <tt>/_pat_/s</tt>: Windows-31J
-
- /foo/s.encoding # => #<Encoding:Windows-31J>
-
-A regexp can be matched against a target string when either:
-
-- 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.
-
-If a match between incompatible encodings is attempted an
-<tt>Encoding::CompatibilityError</tt> exception is raised.
-
-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
-
-The encoding may be explicitly fixed by including Regexp::FIXEDENCODING
-in the second argument for Regexp.new:
-
- # 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.
-
-== Timeouts
-
-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.
-
-\Regexp has two timeout values:
-
-- 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=:
-
- Regexp.timeout # => nil
- Regexp.timeout = 3.0
- Regexp.timeout # => 3.0
-
-- An instance timeout, which defaults to +nil+ and may be set in Regexp.new:
-
- re = Regexp.new('foo', timeout: 5.0)
- re.timeout # => 5.0
-
-When regexp.timeout is +nil+, the timeout "falls through" to Regexp.timeout;
-when regexp.timeout is non-+nil+, that value controls timing out:
-
- | 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. |
-
-== Optimization
-
-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.
-
-\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.
-
-This optimization is applied if the pattern meets these criteria:
-
-- 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)
-
-You can use method Regexp.linear_time? to determine whether a pattern meets these criteria:
-
- Regexp.linear_time?(/a*/) # => true
- Regexp.linear_time?('a*') # => true
- Regexp.linear_time?(/(a*)\1/) # => false
-
-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).
-
-== References
-
-Read (online PDF books):
-
-- {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.
-
-Explore, test (interactive online editor):
-
-- {Rubular}[https://rubular.com/].
diff --git a/doc/_timezones.rdoc b/doc/_timezones.rdoc
deleted file mode 100644
index e355d699b4..0000000000
--- a/doc/_timezones.rdoc
+++ /dev/null
@@ -1,162 +0,0 @@
-== Timezone Specifiers
-
-Certain +Time+ methods accept arguments that specify timezones:
-
-- Time.at: keyword argument +in:+.
-- Time.new: positional argument +zone+ or keyword argument +in:+.
-- Time.now: keyword argument +in:+.
-- Time#getlocal: positional argument +zone+.
-- Time#localtime: positional argument +zone+.
-
-The value given with any of these must be one of the following
-(each detailed below):
-
-- {Hours/minutes offset}[rdoc-ref:Time@Hours-2FMinutes+Offsets].
-- {Single-letter offset}[rdoc-ref:Time@Single-Letter+Offsets].
-- {Integer offset}[rdoc-ref:Time@Integer+Offsets].
-- {Timezone object}[rdoc-ref:Time@Timezone+Objects].
-- {Timezone name}[rdoc-ref:Time@Timezone+Names].
-
-=== Hours/Minutes Offsets
-
-The zone value may be a string offset from UTC
-in the form <tt>'+HH:MM'</tt> or <tt>'-HH:MM'</tt>,
-where:
-
-- +HH+ is the 2-digit hour in the range <tt>0..23</tt>.
-- +MM+ is the 2-digit minute in the range <tt>0..59</tt>.
-
-Examples:
-
- t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
- Time.at(t, in: '-23:59') # => 1999-12-31 20:16:01 -2359
- Time.at(t, in: '+23:59') # => 2000-01-02 20:14:01 +2359
-
-=== Single-Letter Offsets
-
-The zone value may be a letter in the range <tt>'A'..'I'</tt>
-or <tt>'K'..'Z'</tt>;
-see {List of military time zones}[https://en.wikipedia.org/wiki/List_of_military_time_zones]:
-
- t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
- Time.at(t, in: 'A') # => 2000-01-01 21:15:01 +0100
- Time.at(t, in: 'I') # => 2000-01-02 05:15:01 +0900
- Time.at(t, in: 'K') # => 2000-01-02 06:15:01 +1000
- Time.at(t, in: 'Y') # => 2000-01-01 08:15:01 -1200
- Time.at(t, in: 'Z') # => 2000-01-01 20:15:01 UTC
-
-=== \Integer Offsets
-
-The zone value may be an integer number of seconds
-in the range <tt>-86399..86399</tt>:
-
- t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
- Time.at(t, in: -86399) # => 1999-12-31 20:15:02 -235959
- Time.at(t, in: 86399) # => 2000-01-02 20:15:00 +235959
-
-=== Timezone Objects
-
-The zone value may be an object responding to certain timezone methods, an
-instance of {Timezone}[https://github.com/panthomakos/timezone] and
-{TZInfo}[https://tzinfo.github.io] for example.
-
-The timezone methods are:
-
-- +local_to_utc+:
-
- Called when Time.new is invoked with +tz+ as the value of positional
- argument +zone+ or keyword argument +in:+.
-
- Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
- Returns:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the UTC timezone.
-
-- +utc_to_local+:
-
- Called when Time.at or Time.now is invoked with +tz+ as the value for
- keyword argument +in:+, and when Time#getlocal or Time#localtime is called
- with +tz+ as the value for positional argument +zone+.
-
- The UTC offset will be calculated as the difference between the
- original time and the returned object as an +Integer+.
-
- Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
- Returns:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the local timezone.
-
-A custom timezone class may have these instance methods,
-which will be called if defined:
-
-- +abbr+:
-
- Called when Time#strftime is invoked with a format involving <tt>%Z</tt>.
-
- Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
- Returns:: a string abbreviation for the timezone name.
-
-- +dst?+:
-
- Called when Time.at or Time.now is invoked with +tz+ as the value for
- keyword argument +in:+, and when Time#getlocal or Time#localtime is
- called with +tz+ as the value for positional argument +zone+.
-
- Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
- Returns:: whether the time is daylight saving time.
-
-- +name+:
-
- Called when <tt>Marshal.dump(t)</tt> is invoked
-
- Argument:: none.
- Returns:: the string name of the timezone.
-
-==== +Time+-Like Objects
-
-A +Time+-like object is a container object capable of interfacing with
-timezone libraries for timezone conversion.
-
-The argument to the timezone conversion methods above will have attributes
-similar to Time, except that timezone related attributes are meaningless.
-
-The objects returned by +local_to_utc+ and +utc_to_local+ methods of the
-timezone object may be of the same class as their arguments, of arbitrary
-object classes, or of class Integer.
-
-For a returned class other than +Integer+, the class must have the
-following methods:
-
-- +year+
-- +mon+
-- +mday+
-- +hour+
-- +min+
-- +sec+
-- +isdst+
-- +to_i+
-
-For a returned +Integer+, its components, decomposed in UTC, are
-interpreted as times in the specified timezone.
-
-=== Timezone Names
-
-If the class (the receiver of class methods, or the class of the receiver
-of instance methods) has +find_timezone+ singleton method, this method is
-called to achieve the corresponding timezone object from a timezone name.
-
-For example, using {Timezone}[https://github.com/panthomakos/timezone]:
- class TimeWithTimezone < Time
- require 'timezone'
- def self.find_timezone(z) = Timezone[z]
- end
-
- TimeWithTimezone.now(in: "America/New_York") #=> 2023-12-25 00:00:00 -0500
- TimeWithTimezone.new("2023-12-25 America/New_York") #=> 2023-12-25 00:00:00 -0500
-
-Or, using {TZInfo}[https://tzinfo.github.io]:
- class TimeWithTZInfo < Time
- require 'tzinfo'
- def self.find_timezone(z) = TZInfo::Timezone.get(z)
- end
-
- TimeWithTZInfo.now(in: "America/New_York") #=> 2023-12-25 00:00:00 -0500
- TimeWithTZInfo.new("2023-12-25 America/New_York") #=> 2023-12-25 00:00:00 -0500
-
-You can define this method per subclasses, or on the toplevel Time class.
diff --git a/doc/bsearch.rdoc b/doc/bsearch.rdoc
index 90705853d7..ca8091fc0d 100644
--- a/doc/bsearch.rdoc
+++ b/doc/bsearch.rdoc
@@ -1,4 +1,4 @@
-= Binary Searching
+== Binary Searching
A few Ruby methods support binary searching in a collection:
diff --git a/doc/case_mapping.rdoc b/doc/case_mapping.rdoc
index 57c037b9d8..3c42154973 100644
--- a/doc/case_mapping.rdoc
+++ b/doc/case_mapping.rdoc
@@ -1,4 +1,4 @@
-= Case Mapping
+== Case Mapping
Some string-oriented methods use case mapping.
@@ -24,7 +24,7 @@ In Symbol:
- Symbol#swapcase
- Symbol#upcase
-== Default Case Mapping
+=== Default Case Mapping
By default, all of these methods use full Unicode case mapping,
which is suitable for most languages.
@@ -60,7 +60,7 @@ Case changes may not be reversible:
Case changing methods may not maintain Unicode normalization.
See String#unicode_normalize).
-== Options for Case Mapping
+=== Options for Case Mapping
Except for +casecmp+ and +casecmp?+,
each of the case-mapping methods listed above
diff --git a/doc/character_selectors.rdoc b/doc/character_selectors.rdoc
index 47cf242be7..e01b0e6a25 100644
--- a/doc/character_selectors.rdoc
+++ b/doc/character_selectors.rdoc
@@ -1,6 +1,6 @@
-= Character Selectors
+== Character Selectors
-== Character Selector
+=== Character Selector
A _character_ _selector_ is a string argument accepted by certain Ruby methods.
Each of these instance methods accepts one or more character selectors:
@@ -70,7 +70,7 @@ In a character selector, these three characters get special treatment:
"hello\r\nworld".delete("\\r") # => "hello\r\nwold"
"hello\r\nworld".delete("\\\r") # => "hello\nworld"
-== Multiple Character Selectors
+=== Multiple Character Selectors
These instance methods accept multiple character selectors:
diff --git a/doc/command_injection.rdoc b/doc/command_injection.rdoc
index 246b2e6afe..af09be23f0 100644
--- a/doc/command_injection.rdoc
+++ b/doc/command_injection.rdoc
@@ -1,4 +1,4 @@
-= Command Injection
+== Command Injection
Some Ruby core methods accept string data
that includes text to be executed as a system command.
@@ -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 027be34775..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,61 +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).
-
-### Explicit Links
-
-When writing an explicit link, follow these guidelines.
-
-#### +rdoc-ref+ Scheme
-
-Use the +rdoc-ref+ scheme for:
-
-- A link in core documentation to other core documentation.
-- A link in core documentation to documentation in a standard library package.
-- A link in a standard library package to other documentation in that same
- standard library package.
-
-See section "+rdoc-ref+ Scheme" in {Links}[rdoc-ref:RDoc::MarkupReference@Links].
-
-#### URL-Based Link
-
-Use a full URL-based link for:
-
-- A link in standard library documentation to documentation in the core.
-- A link in standard library documentation to documentation in a different
- standard library package.
-
-Doing so ensures that the link will valid even when the package documentation
-is built independently (separately from the core documentation).
-
-The link should lead to a target in https://docs.ruby-lang.org/en/master/.
-
-Also use a full URL-based link for a link to an off-site document.
-
-### 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
@@ -248,21 +175,16 @@ may not render them properly.
In particular, avoid building tables with HTML tags
(<tt><table></tt>, etc.).
-Alternatives:
+Alternatives are:
-- 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:
+- 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/file.c#L6570-L6596].
- - Corresponding {output}[rdoc-ref:File@Read-2FWrite+Mode].
-
-- (Markdown format only): A {Github Flavored Markdown (GFM) table}[https://github.github.com/gfm/#tables-extension-],
- using special formatting for the text:
-
- - 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
@@ -292,12 +214,9 @@ 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.
-- All methods mentioned in the left-pane table of contents
- should be listed (including any methods extended from another class).
-- Attributes (which are not included in the TOC) may also be listed.
-- Display methods as items in one or more bullet lists:
+- List methods as a bullet list:
- Begin each item with the method name, followed by a colon
and a short description.
@@ -305,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.
@@ -322,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)
@@ -330,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:
@@ -408,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
@@ -469,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
@@ -482,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 86c6671fbd..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 hierarchy 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 97c0d22616..1f3c54d740 100644
--- a/doc/encodings.rdoc
+++ b/doc/encodings.rdoc
@@ -1,6 +1,6 @@
-= Encodings
+== Encodings
-== The Basics
+=== The Basics
A {character encoding}[https://en.wikipedia.org/wiki/Character_encoding],
often shortened to _encoding_, is a mapping between:
@@ -30,9 +30,9 @@ Other characters, such as the Euro symbol, are multi-byte:
s = "\u20ac" # => "€"
s.bytes # => [226, 130, 172]
-== The \Encoding \Class
+=== The \Encoding \Class
-=== \Encoding Objects
+==== \Encoding Objects
Ruby encodings are defined by constants in class \Encoding.
There can be only one instance of \Encoding for each of these constants.
@@ -43,7 +43,7 @@ There can be only one instance of \Encoding for each of these constants.
Encoding.list.take(3)
# => [#<Encoding:ASCII-8BIT>, #<Encoding:UTF-8>, #<Encoding:US-ASCII>]
-=== Names and Aliases
+==== Names and Aliases
\Method Encoding#name returns the name of an \Encoding:
@@ -78,7 +78,7 @@ because it includes both the names and their aliases.
Encoding.find("US-ASCII") # => #<Encoding:US-ASCII>
Encoding.find("US-ASCII").class # => Encoding
-=== Default Encodings
+==== Default Encodings
\Method Encoding.find, above, also returns a default \Encoding
for each of these special names:
@@ -118,7 +118,7 @@ for each of these special names:
Encoding.default_internal = 'US-ASCII' # => "US-ASCII"
Encoding.default_internal # => #<Encoding:US-ASCII>
-=== Compatible Encodings
+==== Compatible Encodings
\Method Encoding.compatible? returns whether two given objects are encoding-compatible
(that is, whether they can be concatenated);
@@ -132,21 +132,20 @@ returns the \Encoding of the concatenated string, or +nil+ if incompatible:
s1 = "\xa1\xa1".force_encoding('euc-jp') # => "\x{A1A1}"
Encoding.compatible?(s0, s1) # => nil
-== \String \Encoding
+=== \String \Encoding
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:
@@ -183,7 +182,7 @@ Here are a couple of useful query methods:
s = "\xc2".force_encoding("UTF-8") # => "\xC2"
s.valid_encoding? # => false
-== \Symbol and \Regexp Encodings
+=== \Symbol and \Regexp Encodings
The string stored in a Symbol or Regexp object also has an encoding;
the encoding may be retrieved by method Symbol#encoding or Regexp#encoding.
@@ -191,23 +190,22 @@ 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
+=== Filesystem \Encoding
The filesystem encoding is the default \Encoding for a string from the filesystem:
Encoding.find("filesystem") # => #<Encoding:UTF-8>
-== Locale \Encoding
+=== Locale \Encoding
The locale encoding is the default encoding for a string from the environment,
other than from the filesystem:
Encoding.find('locale') # => #<Encoding:IBM437>
-== Stream Encodings
+=== Stream Encodings
Certain stream objects can have two encodings; these objects include instances of:
@@ -222,7 +220,7 @@ The two encodings are:
- An _internal_ _encoding_, which (if not +nil+) specifies the encoding
to be used for the string constructed from the stream.
-=== External \Encoding
+==== External \Encoding
The external encoding, which is an \Encoding object, specifies how bytes read
from the stream are to be interpreted as characters.
@@ -250,7 +248,7 @@ For an \IO, \File, \ARGF, or \StringIO object, the external encoding may be set
- \Methods +set_encoding+ or (except for \ARGF) +set_encoding_by_bom+.
-=== Internal \Encoding
+==== Internal \Encoding
The internal encoding, which is an \Encoding object or +nil+,
specifies how characters read from the stream
@@ -276,7 +274,7 @@ For an \IO, \File, \ARGF, or \StringIO object, the internal encoding may be set
- \Method +set_encoding+.
-== Script \Encoding
+=== Script \Encoding
A Ruby script has a script encoding, which may be retrieved by:
@@ -291,7 +289,7 @@ followed by a colon, space and the Encoding name or alias:
# encoding: ISO-8859-1
__ENCODING__ #=> #<Encoding:ISO-8859-1>
-== Transcoding
+=== Transcoding
_Transcoding_ is the process of changing a sequence of characters
from one encoding to another.
@@ -302,7 +300,7 @@ but the bytes that represent them may change.
The handling for characters that cannot be represented in the destination encoding
may be specified by @Encoding+Options.
-=== Transcoding a \String
+==== Transcoding a \String
Each of these methods transcodes a string:
@@ -317,7 +315,7 @@ Each of these methods transcodes a string:
- String#unicode_normalize!: Like String#unicode_normalize,
but transcodes +self+ in place.
-== Transcoding a Stream
+=== Transcoding a Stream
Each of these methods may transcode a stream;
whether it does so depends on the external and internal encodings:
@@ -352,7 +350,7 @@ Output:
"R\xE9sum\xE9"
"Résumé"
-== \Encoding Options
+=== \Encoding Options
A number of methods in the Ruby core accept keyword arguments as encoding options.
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 f0e12f27f2..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,66 +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 +RUBY_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(ref_list_name)</code> - Define _ref_list_name_ as a list of references
-
-* <code>RUBY_REF_END</code> - The end mark of the references list.
-
-* <code>RUBY_REF_EDGE(struct, member)</code> - Declare _member_ as a VALUE edge from _struct_. Use this after +RUBY_REFERENCES_START+
-
-* +RUBY_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`.
- // Needs terminating with RUBY_REF_END
- RUBY_REFERENCES(dir_refs) = {
- RUBY_REF_EDGE(dir_data, path),
- RUBY_REF_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",
- {RUBY_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)
@@ -845,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
@@ -1056,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
@@ -1095,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>.
@@ -1120,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
@@ -1129,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
@@ -1162,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
@@ -1171,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
@@ -1179,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
@@ -1193,7 +1136,7 @@ util.c :: misc utilities
gem_prelude.rb
prelude.rb
-=== Class library
+=== Class Library
array.c :: Array
bignum.c :: Bignum
@@ -1232,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
@@ -1248,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 ::
@@ -1262,7 +1205,7 @@ Qfalse ::
false object
-=== C pointer wrapping
+=== C Pointer Wrapping
Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval) ::
@@ -1282,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) ::
@@ -1312,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) ::
@@ -1396,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) ::
@@ -1423,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) ::
@@ -1467,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) ::
@@ -1479,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) ::
@@ -1655,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) ::
@@ -1666,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) ::
@@ -1762,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, ...) ::
@@ -1835,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
@@ -1887,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):
@@ -1912,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) ::
@@ -1954,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/format_specifications.rdoc b/doc/format_specifications.rdoc
index 1111575e74..e589524f27 100644
--- a/doc/format_specifications.rdoc
+++ b/doc/format_specifications.rdoc
@@ -1,4 +1,4 @@
-= Format Specifications
+== Format Specifications
Several Ruby core classes have instance method +printf+ or +sprintf+:
@@ -37,12 +37,12 @@ It consists of:
Except for the leading percent character,
the only required part is the type specifier, so we begin with that.
-== Type Specifiers
+=== Type Specifiers
This section provides a brief explanation of each type specifier.
The links lead to the details and examples.
-=== \Integer Type Specifiers
+==== \Integer Type Specifiers
- +b+ or +B+: Format +argument+ as a binary integer.
See {Specifiers b and B}[rdoc-ref:format_specifications.rdoc@Specifiers+b+and+B].
@@ -54,7 +54,7 @@ The links lead to the details and examples.
- +x+ or +X+: Format +argument+ as a hexadecimal integer.
See {Specifiers x and X}[rdoc-ref:format_specifications.rdoc@Specifiers+x+and+X].
-=== Floating-Point Type Specifiers
+==== Floating-Point Type Specifiers
- +a+ or +A+: Format +argument+ as hexadecimal floating-point number.
See {Specifiers a and A}[rdoc-ref:format_specifications.rdoc@Specifiers+a+and+A].
@@ -65,7 +65,7 @@ The links lead to the details and examples.
- +g+ or +G+: Format +argument+ in a "general" format.
See {Specifiers g and G}[rdoc-ref:format_specifications.rdoc@Specifiers+g+and+G].
-=== Other Type Specifiers
+==== Other Type Specifiers
- +c+: Format +argument+ as a character.
See {Specifier c}[rdoc-ref:format_specifications.rdoc@Specifier+c].
@@ -76,7 +76,7 @@ The links lead to the details and examples.
- <tt>%</tt>: Format +argument+ (<tt>'%'</tt>) as a single percent character.
See {Specifier %}[rdoc-ref:format_specifications.rdoc@Specifier+-25].
-== Flags
+=== Flags
The effect of a flag may vary greatly among type specifiers.
These remarks are general in nature.
@@ -85,7 +85,7 @@ See {type-specific details}[rdoc-ref:format_specifications.rdoc@Type+Specifier+D
Multiple flags may be given with single type specifier;
order does not matter.
-=== <tt>' '</tt> Flag
+==== <tt>' '</tt> Flag
Insert a space before a non-negative number:
@@ -97,49 +97,49 @@ Insert a minus sign for negative value:
sprintf('%d', -10) # => "-10"
sprintf('% d', -10) # => "-10"
-=== <tt>'#'</tt> Flag
+==== <tt>'#'</tt> Flag
Use an alternate format; varies among types:
sprintf('%x', 100) # => "64"
sprintf('%#x', 100) # => "0x64"
-=== <tt>'+'</tt> Flag
+==== <tt>'+'</tt> Flag
Add a leading plus sign for a non-negative number:
sprintf('%x', 100) # => "64"
sprintf('%+x', 100) # => "+64"
-=== <tt>'-'</tt> Flag
+==== <tt>'-'</tt> Flag
Left justify the value in its field:
sprintf('%6d', 100) # => " 100"
sprintf('%-6d', 100) # => "100 "
-=== <tt>'0'</tt> Flag
+==== <tt>'0'</tt> Flag
Left-pad with zeros instead of spaces:
sprintf('%6d', 100) # => " 100"
sprintf('%06d', 100) # => "000100"
-=== <tt>'*'</tt> Flag
+==== <tt>'*'</tt> Flag
Use the next argument as the field width:
sprintf('%d', 20, 14) # => "20"
sprintf('%*d', 20, 14) # => " 14"
-=== <tt>'n$'</tt> Flag
+==== <tt>'n$'</tt> Flag
Format the (1-based) <tt>n</tt>th argument into this field:
sprintf("%s %s", 'world', 'hello') # => "world hello"
sprintf("%2$s %1$s", 'world', 'hello') # => "hello world"
-== Width Specifier
+=== Width Specifier
In general, a width specifier determines the minimum width (in characters)
of the formatted field:
@@ -152,7 +152,7 @@ of the formatted field:
# Ignore if too small.
sprintf('%1d', 100) # => "100"
-== Precision Specifier
+=== Precision Specifier
A precision specifier is a decimal point followed by zero or more
decimal digits.
@@ -194,9 +194,9 @@ the number of characters to write:
sprintf('%s', Time.now) # => "2022-05-04 11:59:16 -0400"
sprintf('%.10s', Time.now) # => "2022-05-04"
-== Type Specifier Details and Examples
+=== Type Specifier Details and Examples
-=== Specifiers +a+ and +A+
+==== Specifiers +a+ and +A+
Format +argument+ as hexadecimal floating-point number:
@@ -209,7 +209,7 @@ Format +argument+ as hexadecimal floating-point number:
sprintf('%A', 4096) # => "0X1P+12"
sprintf('%A', -4096) # => "-0X1P+12"
-=== Specifiers +b+ and +B+
+==== Specifiers +b+ and +B+
The two specifiers +b+ and +B+ behave identically
except when flag <tt>'#'</tt>+ is used.
@@ -226,14 +226,14 @@ Format +argument+ as a binary integer:
sprintf('%#b', 4) # => "0b100"
sprintf('%#B', 4) # => "0B100"
-=== Specifier +c+
+==== Specifier +c+
Format +argument+ as a single character:
sprintf('%c', 'A') # => "A"
sprintf('%c', 65) # => "A"
-=== Specifier +d+
+==== Specifier +d+
Format +argument+ as a decimal integer:
@@ -242,7 +242,7 @@ Format +argument+ as a decimal integer:
Flag <tt>'#'</tt> does not apply.
-=== Specifiers +e+ and +E+
+==== Specifiers +e+ and +E+
Format +argument+ in
{scientific notation}[https://en.wikipedia.org/wiki/Scientific_notation]:
@@ -250,7 +250,7 @@ Format +argument+ in
sprintf('%e', 3.14159) # => "3.141590e+00"
sprintf('%E', -3.14159) # => "-3.141590E+00"
-=== Specifier +f+
+==== Specifier +f+
Format +argument+ as a floating-point number:
@@ -259,7 +259,7 @@ Format +argument+ as a floating-point number:
Flag <tt>'#'</tt> does not apply.
-=== Specifiers +g+ and +G+
+==== Specifiers +g+ and +G+
Format +argument+ using exponential form (+e+/+E+ specifier)
if the exponent is less than -4 or greater than or equal to the precision.
@@ -281,7 +281,7 @@ Otherwise format +argument+ using floating-point form (+f+ specifier):
sprintf('%#G', 100000000000) # => "1.00000E+11"
sprintf('%#G', 0.000000000001) # => "1.00000E-12"
-=== Specifier +o+
+==== Specifier +o+
Format +argument+ as an octal integer.
If +argument+ is negative, it will be formatted as a two's complement
@@ -296,14 +296,14 @@ prefixed with +..7+:
sprintf('%#o', 16) # => "020"
sprintf('%#o', -16) # => "..760"
-=== Specifier +p+
+==== Specifier +p+
Format +argument+ as a string via <tt>argument.inspect</tt>:
t = Time.now
sprintf('%p', t) # => "2022-05-01 13:42:07.1645683 -0500"
-=== Specifier +s+
+==== Specifier +s+
Format +argument+ as a string via <tt>argument.to_s</tt>:
@@ -312,7 +312,7 @@ Format +argument+ as a string via <tt>argument.to_s</tt>:
Flag <tt>'#'</tt> does not apply.
-=== Specifiers +x+ and +X+
+==== Specifiers +x+ and +X+
Format +argument+ as a hexadecimal integer.
If +argument+ is negative, it will be formatted as a two's complement
@@ -329,7 +329,7 @@ prefixed with +..f+:
# Alternate format for negative value.
sprintf('%#x', -100) # => "0x..f9c"
-=== Specifier <tt>%</tt>
+==== Specifier <tt>%</tt>
Format +argument+ (<tt>'%'</tt>) as a single percent character:
@@ -337,7 +337,7 @@ Format +argument+ (<tt>'%'</tt>) as a single percent character:
Flags do not apply.
-== Reference by Name
+=== Reference by Name
For more complex formatting, Ruby supports a reference by name.
%<name>s style uses format style, but %{name} style doesn't.
diff --git a/doc/globals.rdoc b/doc/globals.rdoc
index 1bf78a60ab..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>>
-
-== Environment
-
-=== 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/implicit_conversion.rdoc b/doc/implicit_conversion.rdoc
index e244096125..ba15fa4bf4 100644
--- a/doc/implicit_conversion.rdoc
+++ b/doc/implicit_conversion.rdoc
@@ -1,4 +1,4 @@
-= Implicit Conversions
+== Implicit Conversions
Some Ruby methods accept one or more objects
that can be either:
@@ -15,7 +15,7 @@ a specific conversion method:
* Integer: +to_int+
* String: +to_str+
-== Array-Convertible Objects
+=== Array-Convertible Objects
An <i>Array-convertible object</i> is an object that:
@@ -69,7 +69,7 @@ This class is not Array-convertible (method +to_ary+ returns non-Array):
# Raises TypeError (can't convert NotArrayConvertible to Array (NotArrayConvertible#to_ary gives Symbol))
a.replace(NotArrayConvertible.new)
-== Hash-Convertible Objects
+=== Hash-Convertible Objects
A <i>Hash-convertible object</i> is an object that:
@@ -123,7 +123,7 @@ This class is not Hash-convertible (method +to_hash+ returns non-Hash):
# Raises TypeError (can't convert NotHashConvertible to Hash (ToHashReturnsNonHash#to_hash gives Symbol))
h.merge(NotHashConvertible.new)
-== Integer-Convertible Objects
+=== Integer-Convertible Objects
An <i>Integer-convertible object</i> is an object that:
@@ -171,7 +171,7 @@ This class is not Integer-convertible (method +to_int+ returns non-Integer):
# Raises TypeError (can't convert NotIntegerConvertible to Integer (NotIntegerConvertible#to_int gives Symbol))
Array.new(NotIntegerConvertible.new)
-== String-Convertible Objects
+=== String-Convertible Objects
A <i>String-convertible object</i> is an object that:
* Has instance method +to_str+.
diff --git a/doc/irb/indexes.md b/doc/irb/indexes.md
deleted file mode 100644
index 24a67b9698..0000000000
--- a/doc/irb/indexes.md
+++ /dev/null
@@ -1,189 +0,0 @@
-## Indexes
-
-### Index of Command-Line Options
-
-These are the \IRB command-line options, with links to explanatory text:
-
-- `-d`: Set `$DEBUG` and {$VERBOSE}[rdoc-ref:IRB@Verbosity]
- to `true`.
-- `-E _ex_[:_in_]`: Set initial external (ex) and internal (in)
- {encodings}[rdoc-ref:IRB@Encodings] (same as `ruby -E>`).
-- `-f`: Don't initialize from {configuration file}[rdoc-ref:IRB@Configuration+File].
-- `-I _dirpath_`: Specify {$LOAD_PATH directory}[rdoc-ref:IRB@Load+Modules]
- (same as `ruby -I`).
-- `-r _load-module_`: Require {load-module}[rdoc-ref:IRB@Load+Modules]
- (same as `ruby -r`).
-- `-U`: Set external and internal {encodings}[rdoc-ref:IRB@Encodings] to UTF-8.
-- `-w`: Suppress {warnings}[rdoc-ref:IRB@Warnings] (same as `ruby -w`).
-- `-W[_level_]`: Set {warning level}[rdoc-ref:IRB@Warnings];
- 0=silence, 1=medium, 2=verbose (same as `ruby -W`).
-- `--autocomplete`: Use {auto-completion}[rdoc-ref:IRB@Automatic+Completion].
-- `--back-trace-limit _n_`: Set a {backtrace limit}[rdoc-ref:IRB@Tracer];
- display at most the top `n` and bottom `n` entries.
-- `--colorize`: Use {color-highlighting}[rdoc-ref:IRB@Color+Highlighting]
- for input and output.
-- `--context-mode _n_`: Select method to create Binding object
- for new {workspace}[rdoc-ref:IRB@Commands]; `n` in range `0..4`.
-- `--echo`: Print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values.
-- `--extra-doc-dir _dirpath_`:
- Add a {documentation directory}[rdoc-ref:IRB@RI+Documentation+Directories]
- for the documentation dialog.
-- `--inf-ruby-mode`: Set prompt mode to {:INF_RUBY}[rdoc-ref:IRB@Pre-Defined+Prompts]
- (appropriate for `inf-ruby-mode` on Emacs);
- suppresses --multiline and --singleline.
-- `--inspect`: Use method `inspect` for printing ({echoing}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values.
-- `--multiline`: Use the multiline editor as the {input method}[rdoc-ref:IRB@Input+Method].
-- `--noautocomplete`: Don't use {auto-completion}[rdoc-ref:IRB@Automatic+Completion].
-- `--nocolorize`: Don't use {color-highlighting}[rdoc-ref:IRB@Color+Highlighting]
- for input and output.
-- `--noecho`: Don't print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values.
-- `--noecho-on-assignment`: Don't print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- result on assignment.
-- `--noinspect`: Don't se method `inspect` for printing ({echoing}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values.
-- `--nomultiline`: Don't use the multiline editor as the {input method}[rdoc-ref:IRB@Input+Method].
-- `--noprompt`: Don't print {prompts}[rdoc-ref:IRB@Prompt+and+Return+Formats].
-- `--noscript`: Treat the first command-line argument as a normal
- {command-line argument}[rdoc-ref:IRB@Initialization+Script],
- and include it in `ARGV`.
-- `--nosingleline`: Don't use the singleline editor as the {input method}[rdoc-ref:IRB@Input+Method].
-- `--noverbose`Don't print {verbose}[rdoc-ref:IRB@Verbosity] details.
-- `--prompt _mode_`, `--prompt-mode _mode_`:
- Set {prompt and return formats}[rdoc-ref:IRB@Prompt+and+Return+Formats];
- `mode` may be a {pre-defined prompt}[rdoc-ref:IRB@Pre-Defined+Prompts]
- or the name of a {custom prompt}[rdoc-ref:IRB@Custom+Prompts].
-- `--script`: Treat the first command-line argument as the path to an
- {initialization script}[rdoc-ref:IRB@Initialization+Script],
- and omit it from `ARGV`.
-- `--simple-prompt`, `--sample-book-mode`:
- Set prompt mode to {:SIMPLE}[rdoc-ref:IRB@Pre-Defined+Prompts].
-- `--singleline`: Use the singleline editor as the {input method}[rdoc-ref:IRB@Input+Method].
-- `--tracer`: Use {Tracer}[rdoc-ref:IRB@Tracer] to print a stack trace for each input command.
-- `--truncate-echo-on-assignment`: Print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- truncated result on assignment.
-- `--verbose`Print {verbose}[rdoc-ref:IRB@Verbosity] details.
-- `-v`, `--version`: Print the {IRB version}[rdoc-ref:IRB@Version].
-- `-h`, `--help`: Print the {IRB help text}[rdoc-ref:IRB@Help].
-- `--`: Separate options from {arguments}[rdoc-ref:IRB@Command-Line+Arguments]
- on the command-line.
-
-### Index of \IRB.conf Entries
-
-These are the keys for hash \IRB.conf entries, with links to explanatory text;
-for each entry that is pre-defined, the initial value is given:
-
-- `:AP_NAME`: \IRB {application name}[rdoc-ref:IRB@Application+Name];
- initial value: `'irb'`.
-- `:AT_EXIT`: Array of hooks to call
- {at exit}[rdoc-ref:IRB@IRB];
- initial value: `[]`.
-- `:AUTO_INDENT`: Whether {automatic indentation}[rdoc-ref:IRB@Automatic+Indentation]
- is enabled; initial value: `true`.
-- `:BACK_TRACE_LIMIT`: Sets the {back trace limit}[rdoc-ref:IRB@Tracer];
- initial value: `16`.
-- `:COMMAND_ALIASES`: Defines input {command aliases}[rdoc-ref:IRB@Command+Aliases];
- initial value:
-
- {
- "$": :show_source,
- "@": :whereami,
- }
-
-- `:CONTEXT_MODE`: Sets the {context mode}[rdoc-ref:IRB@Context+Mode],
- the type of binding to be used when evaluating statements;
- initial value: `4`.
-- `:ECHO`: Whether to print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values;
- initial value: `nil`, which would set `conf.echo` to `true`.
-- `:ECHO_ON_ASSIGNMENT`: Whether to print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values on assignment;
- initial value: `nil`, which would set `conf.echo_on_assignment` to `:truncate`.
-- `:EVAL_HISTORY`: How much {evaluation history}[rdoc-ref:IRB@Evaluation+History]
- is to be stored; initial value: `nil`.
-- `:EXTRA_DOC_DIRS`: \Array of
- {RI documentation directories}[rdoc-ref:IRB@RI+Documentation+Directories]
- to be parsed for the documentation dialog;
- initial value: `[]`.
-- `:IGNORE_EOF`: Whether to ignore {end-of-file}[rdoc-ref:IRB@End-of-File];
- initial value: `false`.
-- `:IGNORE_SIGINT`: Whether to ignore {SIGINT}[rdoc-ref:IRB@SIGINT];
- initial value: `true`.
-- `:INSPECT_MODE`: Whether to use method `inspect` for printing
- ({echoing}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29]) return values;
- initial value: `true`.
-- `:IRB_LIB_PATH`: The path to the {IRB library directory}[rdoc-ref:IRB@IRB+Library+Directory]; initial value:
-
- - `"<i>RUBY_DIR</i>/lib/ruby/gems/<i>RUBY_VER_NUM</i>/gems/irb-<i>IRB_VER_NUM</i>/lib/irb"`,
-
- where:
-
- - <i>RUBY_DIR</i> is the Ruby installation dirpath.
- - <i>RUBY_VER_NUM</i> is the Ruby version number.
- - <i>IRB_VER_NUM</i> is the \IRB version number.
-
-- `:IRB_NAME`: {IRB name}[rdoc-ref:IRB@IRB+Name];
- initial value: `'irb'`.
-- `:IRB_RC`: {Configuration monitor}[rdoc-ref:IRB@Configuration+Monitor];
- initial value: `nil`.
-- `:LC_MESSAGES`: {Locale}[rdoc-ref:IRB@Locale];
- initial value: IRB::Locale object.
-- `:LOAD_MODULES`: deprecated.
-- `:MAIN_CONTEXT`: The {context}[rdoc-ref:IRB@Session+Context] for the main \IRB session;
- initial value: IRB::Context object.
-- `:MEASURE`: Whether to
- {measure performance}[rdoc-ref:IRB@Performance+Measurement];
- initial value: `false`.
-- `:MEASURE_CALLBACKS`: Callback methods for
- {performance measurement}[rdoc-ref:IRB@Performance+Measurement];
- initial value: `[]`.
-- `:MEASURE_PROC`: Procs for
- {performance measurement}[rdoc-ref:IRB@Performance+Measurement];
- initial value:
-
- {
- :TIME=>#<Proc:0x0000556e271c6598 /var/lib/gems/3.0.0/gems/irb-1.8.3/lib/irb/init.rb:106>,
- :STACKPROF=>#<Proc:0x0000556e271c6548 /var/lib/gems/3.0.0/gems/irb-1.8.3/lib/irb/init.rb:116>
- }
-
-- `:PROMPT`: \Hash of {defined prompts}[rdoc-ref:IRB@Prompt+and+Return+Formats];
- initial value:
-
- {
- :NULL=>{:PROMPT_I=>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* ", :RETURN=>"=> %s\n"},
- :CLASSIC=>{:PROMPT_I=>"%N(%m):%03n:%i> ", :PROMPT_S=>"%N(%m):%03n:%i%l ", :PROMPT_C=>"%N(%m):%03n:%i* ", :RETURN=>"%s\n"},
- :SIMPLE=>{:PROMPT_I=>">> ", :PROMPT_S=>"%l> ", :PROMPT_C=>"?> ", :RETURN=>"=> %s\n"},
- :INF_RUBY=>{:PROMPT_I=>"%N(%m):%03n> ", :PROMPT_S=>nil, :PROMPT_C=>nil, :RETURN=>"%s\n", :AUTO_INDENT=>true},
- :XMP=>{:PROMPT_I=>nil, :PROMPT_S=>nil, :PROMPT_C=>nil, :RETURN=>" ==>%s\n"}
- }
-
-- `:PROMPT_MODE`: Name of {current prompt}[rdoc-ref:IRB@Prompt+and+Return+Formats];
- initial value: `:DEFAULT`.
-- `:RC`: Whether a {configuration file}[rdoc-ref:IRB@Configuration+File]
- was found and interpreted;
- initial value: `true` if a configuration file was found, `false` otherwise.
-- `:SAVE_HISTORY`: Number of commands to save in
- {input command history}[rdoc-ref:IRB@Input+Command+History];
- initial value: `1000`.
-- `:SINGLE_IRB`: Whether command-line option `--single-irb` was given;
- initial value: `true` if the option was given, `false` otherwise.
- See {Single-IRB Mode}[rdoc-ref:IRB@Single-IRB+Mode].
-- `:USE_AUTOCOMPLETE`: Whether to use
- {automatic completion}[rdoc-ref:IRB@Automatic+Completion];
- initial value: `true`.
-- `:USE_COLORIZE`: Whether to use
- {color highlighting}[rdoc-ref:IRB@Color+Highlighting];
- initial value: `true`.
-- `:USE_LOADER`: Whether to use the
- {IRB loader}[rdoc-ref:IRB@IRB+Loader] for `require` and `load`;
- initial value: `false`.
-- `:USE_TRACER`: Whether to use the
- {IRB tracer}[rdoc-ref:IRB@Tracer];
- initial value: `false`.
-- `:VERBOSE`: Whether to print {verbose output}[rdoc-ref:IRB@Verbosity];
- initial value: `nil`.
-- `:__MAIN__`: The main \IRB object;
- initial value: `main`.
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/keywords.rdoc b/doc/keywords.rdoc
index 7c368205ef..cb1cff33f0 100644
--- a/doc/keywords.rdoc
+++ b/doc/keywords.rdoc
@@ -1,4 +1,4 @@
-= Keywords
+== Keywords
The following keywords are used by Ruby.
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/net-http/examples.rdoc b/doc/net-http/examples.rdoc
index c1366e7ad1..dd4acecda6 100644
--- a/doc/net-http/examples.rdoc
+++ b/doc/net-http/examples.rdoc
@@ -10,10 +10,9 @@ Many code examples here use these example websites:
Some examples also assume these variables:
- uri = URI('https://jsonplaceholder.typicode.com/')
+ uri = URI('https://jsonplaceholder.typicode.com')
uri.freeze # Examples may not modify.
hostname = uri.hostname # => "jsonplaceholder.typicode.com"
- path = uri.path # => "/"
port = uri.port # => 443
So that example requests may be written as:
diff --git a/doc/net-http/included_getters.rdoc b/doc/net-http/included_getters.rdoc
deleted file mode 100644
index 7ac327f4b4..0000000000
--- a/doc/net-http/included_getters.rdoc
+++ /dev/null
@@ -1,3 +0,0 @@
-This class also includes (indirectly) module Net::HTTPHeader,
-which gives access to its
-{methods for getting headers}[rdoc-ref:Net::HTTPHeader@Getters].
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 59d8c99a3a..ec13b24c69 100644
--- a/doc/packed_data.rdoc
+++ b/doc/packed_data.rdoc
@@ -1,4 +1,4 @@
-= Packed \Data
+== Packed \Data
Certain Ruby core methods deal with packing and unpacking data:
@@ -64,7 +64,7 @@ If elements don't fit the provided directive, only least significant bits are en
[257].pack("C").unpack("C") # => [1]
-== Packing \Method
+=== Packing \Method
\Method Array#pack accepts optional keyword argument
+buffer+ that specifies the target string (instead of a new string):
@@ -76,7 +76,7 @@ The method can accept a block:
# Packed string is passed to the block.
[65, 66].pack('C*') {|s| p s } # => "AB"
-== Unpacking Methods
+=== Unpacking Methods
Methods String#unpack and String#unpack1 each accept
an optional keyword argument +offset+ that specifies an offset
@@ -95,12 +95,12 @@ Both methods can accept a block:
# The single unpacked object is passed to the block.
'AB'.unpack1('C*') {|ele| p ele } # => 65
-== \Integer Directives
+=== \Integer Directives
Each integer directive specifies the packing or unpacking
for one element in the input or output array.
-=== 8-Bit \Integer Directives
+==== 8-Bit \Integer Directives
- <tt>'c'</tt> - 8-bit signed integer
(like C <tt>signed char</tt>):
@@ -109,14 +109,14 @@ 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"
s = [0, 1, -1].pack('C*') # => "\x00\x01\xFF"
s.unpack('C*') # => [0, 1, 255]
-=== 16-Bit \Integer Directives
+==== 16-Bit \Integer Directives
- <tt>'s'</tt> - 16-bit signed integer, native-endian
(like C <tt>int16_t</tt>):
@@ -146,7 +146,7 @@ for one element in the input or output array.
s.unpack('v*')
# => [0, 1, 65535, 32767, 32768, 65535]
-=== 32-Bit \Integer Directives
+==== 32-Bit \Integer Directives
- <tt>'l'</tt> - 32-bit signed integer, native-endian
(like C <tt>int32_t</tt>):
@@ -178,7 +178,7 @@ for one element in the input or output array.
s.unpack('v*')
# => [0, 0, 1, 0, 65535, 65535]
-=== 64-Bit \Integer Directives
+==== 64-Bit \Integer Directives
- <tt>'q'</tt> - 64-bit signed integer, native-endian
(like C <tt>int64_t</tt>):
@@ -196,7 +196,7 @@ for one element in the input or output array.
s.unpack('Q*')
# => [578437695752307201, 17940646550795321087]
-=== Platform-Dependent \Integer Directives
+==== Platform-Dependent \Integer Directives
- <tt>'i'</tt> - Platform-dependent width signed integer,
native-endian (like C <tt>int</tt>):
@@ -214,24 +214,26 @@ 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"
s.unpack('J*')
# => [67305985, 4244504319]
-=== Other \Integer Directives
-
+==== Other \Integer Directives
+:
- <tt>'U'</tt> - UTF-8 character:
s = [4194304].pack('U*')
@@ -247,30 +249,31 @@ for one element in the input or output array.
s.unpack('w*')
# => [1073741823]
-=== 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:
-
+==== Modifiers for \Integer Directives
+
+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.
-== \Float Directives
+=== \Float Directives
Each float directive specifies the packing or unpacking
for one element in the input or output array.
-=== Single-Precision \Float Directives
+==== Single-Precision \Float Directives
- <tt>'F'</tt> or <tt>'f'</tt> - Native format:
@@ -287,7 +290,7 @@ for one element in the input or output array.
s = [3.0].pack('g') # => "@@\x00\x00"
s.unpack('g') # => [3.0]
-=== Double-Precision \Float Directives
+==== Double-Precision \Float Directives
- <tt>'D'</tt> or <tt>'d'</tt> - Native format:
@@ -314,12 +317,12 @@ A float directive may be infinity or not-a-number:
[nan].pack('f') # => "\x00\x00\xC0\x7F"
"\x00\x00\xC0\x7F".unpack('f') # => [NaN]
-== \String Directives
+=== \String Directives
Each string directive specifies the packing or unpacking
for one byte in the input or output string.
-=== Binary \String Directives
+==== Binary \String Directives
- <tt>'A'</tt> - Arbitrary binary string (space padded; count is width);
+nil+ is treated as the empty string:
@@ -377,7 +380,7 @@ for one byte in the input or output string.
"foo".unpack('Z*') # => ["foo"]
"foo\0bar".unpack('Z*') # => ["foo"] # Does not read past "\0".
-=== Bit \String Directives
+==== Bit \String Directives
- <tt>'B'</tt> - Bit string (high byte first):
@@ -421,7 +424,7 @@ for one byte in the input or output string.
"\x01".unpack("b2") # => ["10"]
"\x01".unpack("b3") # => ["100"]
-=== Hex \String Directives
+==== Hex \String Directives
- <tt>'H'</tt> - Hex string (high nibble first):
@@ -467,7 +470,7 @@ for one byte in the input or output string.
"\x01\xfe".unpack('h4') # => ["10ef"]
"\x01\xfe".unpack('h5') # => ["10ef"]
-=== Pointer \String Directives
+==== Pointer \String Directives
- <tt>'P'</tt> - Pointer to a structure (fixed-length string):
@@ -485,7 +488,7 @@ for one byte in the input or output string.
("\0" * 8).unpack("p") # => [nil]
[nil].pack("p") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
-=== Other \String Directives
+==== Other \String Directives
- <tt>'M'</tt> - Quoted printable, MIME encoding;
text mode, but input must use LF and output LF;
@@ -559,7 +562,7 @@ for one byte in the input or output string.
[0x40000000].pack("U") # => "\xFD\x80\x80\x80\x80\x80"
[0x7fffffff].pack("U") # => "\xFD\xBF\xBF\xBF\xBF\xBF"
-== Offset Directives
+=== Offset Directives
- <tt>'@'</tt> - Begin packing at the given byte offset;
for packing, null fill if necessary:
@@ -577,7 +580,7 @@ for one byte in the input or output string.
[0, 1, 2].pack("CCX2C") # => "\x02"
"\x00\x02".unpack("CCXC") # => [0, 2, 2]
-== Null Byte Direcive
+=== Null Byte Direcive
- <tt>'x'</tt> - Null byte:
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 a1bbe13e2d..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."
#
@@ -467,32 +467,8 @@ require 'rdoc'
#
# - Appended to a line of code
# that defines a class, module, method, alias, constant, or attribute.
-#
# - Specifies that the defined object should not be documented.
#
-# - For method definitions in C code, it must be placed before the
-# implementation:
-#
-# /* :nodoc: */
-# static VALUE
-# some_method(VALUE self)
-# {
-# return self;
-# }
-#
-# Note that this directive has <em>no effect at all</em> at method
-# definition places. E.g.,
-#
-# /* :nodoc: */
-# rb_define_method(cMyClass, "do_something", something_func, 0);
-#
-# The above comment is just a comment and has nothing to do with \RDoc.
-# Therefore, +do_something+ method will be reported as "undocumented"
-# unless that method or function is documented elsewhere.
-#
-# - For constant definitions in C code, this directive <em>can not work</em>
-# because there is no "implementation" place for constants.
-#
# - <tt># :nodoc: all</tt>:
#
# - Appended to a line of code
@@ -526,8 +502,8 @@ require 'rdoc'
# #++
# # Documented.
#
-# For C code, any of directives <tt>:startdoc:</tt>, <tt>:stopdoc:</tt>,
-# and <tt>:enddoc:</tt> may appear in a stand-alone comment:
+# For C code, any of directives <tt>:startdoc:</tt>, <tt>:enddoc:</tt>,
+# and <tt>:nodoc:</tt> may appear in a stand-alone comment:
#
# /* :startdoc: */
# /* :stopdoc: */
@@ -1216,26 +1192,13 @@ require 'rdoc'
#
class RDoc::MarkupReference
- # example class
class DummyClass; end
-
- # example module
module DummyModule; end
-
- # example singleton method
def self.dummy_singleton_method(foo, bar); end
-
- # example instance method
def dummy_instance_method(foo, bar); end;
-
alias dummy_instance_alias dummy_instance_method
-
- # example attribute
attr_accessor :dummy_attribute
-
alias dummy_attribute_alias dummy_attribute
-
- # example constant
DUMMY_CONSTANT = ''
# :call-seq:
diff --git a/doc/regexp.rdoc b/doc/regexp.rdoc
new file mode 100644
index 0000000000..92c7ecf66e
--- /dev/null
+++ b/doc/regexp.rdoc
@@ -0,0 +1,801 @@
+# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*-
+
+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.
+
+A regexp is usually delimited with forward slashes (<tt>/</tt>). For
+example:
+
+ /hay/ =~ 'haystack' #=> 0
+ /y/.match('haystack') #=> #<MatchData "y">
+
+If a string contains the pattern it is said to <i>match</i>. A literal
+string matches itself.
+
+Here 'haystack' does not contain the pattern 'needle', so it doesn't match:
+
+ /needle/.match('haystack') #=> nil
+
+Here 'haystack' contains the pattern 'hay', so it matches:
+
+ /hay/.match('haystack') #=> #<MatchData "hay">
+
+Specifically, <tt>/st/</tt> requires that the string contains the letter
+_s_ followed by the letter _t_, so it matches _haystack_, also.
+
+Note that any Regexp matching will raise a RuntimeError if timeout is set and
+exceeded. See {"Timeout"}[#label-Timeout] section in detail.
+
+== \Regexp Interpolation
+
+A regexp may contain interpolated strings; trivially:
+
+ foo = 'bar'
+ /#{foo}/ # => /bar/
+
+== <tt>=~</tt> and Regexp#match
+
+Pattern matching may be achieved by using <tt>=~</tt> operator or Regexp#match
+method.
+
+=== <tt>=~</tt> Operator
+
+<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+.
+
+ /hay/ =~ 'haystack' #=> 0
+ 'haystack' =~ /hay/ #=> 0
+ /a/ =~ 'haystack' #=> 1
+ /u/ =~ 'haystack' #=> nil
+
+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>.
+
+=== Regexp#match Method
+
+The #match method returns a MatchData object:
+
+ /st/.match('haystack') #=> #<MatchData "st">
+
+== Metacharacters and Escapes
+
+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>.
+
+ /1 \+ 2 = 3\?/.match('Does 1 + 2 = 3?') #=> #<MatchData "1 + 2 = 3?">
+ /a\\\\b/.match('a\\\\b') #=> #<MatchData "a\\b">
+
+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]).
+
+ /\s\u{6771 4eac 90fd}/.match("Go to 東京都")
+ #=> #<MatchData " 東京都">
+
+Arbitrary Ruby expressions can be embedded into patterns with the
+<tt>#{...}</tt> construct.
+
+ place = "東京都"
+ /#{place}/.match("Go to 東京都")
+ #=> #<MatchData "東京都">
+
+== Character Classes
+
+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_.
+
+ /W[aeiou]rd/.match("Word") #=> #<MatchData "Word">
+
+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.
+
+ /[0-9a-f]/.match('9f') #=> #<MatchData "9">
+ /[9f]/.match('9f') #=> #<MatchData "9">
+
+If the first character of a character class is a caret (<tt>^</tt>) the
+class is inverted: it matches any character _except_ those named.
+
+ /[^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))
+
+This is equivalent to:
+
+ /[abh-w]/
+
+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)
+
+Ruby also supports the following non-POSIX character classes:
+
+* <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
+
+ # 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">
+
+== Repetition
+
+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>.
+
+* <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
+
+At least one uppercase character ('H'), at least one lowercase character
+('e'), two 'l' characters, then one 'o':
+
+ "Hello".match(/[[:upper:]]+[[:lower:]]+l{2}o/) #=> #<MatchData "Hello">
+
+=== Greedy Match
+
+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.
+
+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>':
+
+ /<.+>/.match("<a><b>") #=> #<MatchData "<a><b>">
+ /<.+?>/.match("<a><b>") #=> #<MatchData "<a>">
+
+=== Possessive Match
+
+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.
+
+ /<.*><.+>/.match("<a><b>") #=> #<MatchData "<a><b>">
+ /<.*+><.+>/.match("<a><b>") #=> nil
+ /<.*><.++>/.match("<a><b>") #=> nil
+
+== Capturing
+
+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>).
+
+In this example, <tt>'at'</tt> is captured by the first group of
+parentheses, then referred to later with <tt>\1</tt>:
+
+ /[csh](..) [csh]\1 in/.match("The cat sat in the hat")
+ #=> #<MatchData "cat sat in" 1:"at">
+
+Regexp#match returns a MatchData object which makes the captured text
+available with its #[] method:
+
+ /[csh](..) [csh]\1 in/.match("The cat sat in the hat")[1] #=> 'at'
+
+While Ruby supports an arbitrary number of numbered captured groups,
+only groups 1-9 are supported using the <tt>\n</tt> backreference
+syntax.
+
+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 cats sats in the hats"
+
+=== Named Captures
+
+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.
+
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")
+ #=> #<MatchData "$3.67" dollars:"3" cents:"67">
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")[:dollars] #=> "3"
+
+Named groups can be backreferenced with <tt>\k<</tt><i>name</i><tt>></tt>,
+where _name_ is the group name.
+
+ /(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
+ #=> #<MatchData "ototo" vowel:"o">
+
+*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.
+
+ /(\w)(\w)/.match("ab").captures # => ["a", "b"]
+ /(\w)(\w)/.match("ab").named_captures # => {}
+
+ /(?<c>\w)(\w)/.match("ab").captures # => ["a"]
+ /(?<c>\w)(\w)/.match("ab").named_captures # => {"c"=>"a"}
+
+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.
+
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ "$3.67" #=> 0
+ dollars #=> "3"
+
+== Grouping
+
+Parentheses also <i>group</i> the terms they enclose, allowing them to be
+quantified as one <i>atomic</i> whole.
+
+The pattern below matches a vowel followed by 2 word characters:
+
+ /[aeiou]\w{2}/.match("Caenorhabditis elegans") #=> #<MatchData "aen">
+
+Whereas the following pattern matches a vowel followed by a word character,
+twice, i.e. <tt>[aeiou]\w[aeiou]\w</tt>: 'enor'.
+
+ /([aeiou]\w){2}/.match("Caenorhabditis elegans")
+ #=> #<MatchData "enor" 1:"or">
+
+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.
+
+The first group of parentheses captures 'n' and the second 'ti'. The second
+group is referred to later with the backreference <tt>\2</tt>:
+
+ /I(n)ves(ti)ga\2ons/.match("Investigations")
+ #=> #<MatchData "Investigations" 1:"n" 2:"ti">
+
+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'.
+
+ /I(?:n)ves(ti)ga\1ons/.match("Investigations")
+ #=> #<MatchData "Investigations" 1:"ti">
+
+=== Atomic Grouping
+
+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>
+
+ /".*"/.match('"Quote"') #=> #<MatchData "\"Quote\"">
+
+If <tt>.*</tt> is grouped atomically, it refuses to backtrack <i>Quote"</i>,
+even though this means that the overall match fails
+
+ /"(?>.*)"/.match('"Quote"') #=> nil
+
+== Subexpression Calls
+
+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.
+
+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>:
+
+ /\A(?<paren>\(\g<paren>*\))*\z/ =~ '()'
+
+
+ /\A(?<paren>\(\g<paren>*\))*\z/ =~ '(())' #=> 0
+ # ^1
+ # ^2
+ # ^3
+ # ^4
+ # ^5
+ # ^6
+ # ^7
+ # ^8
+ # ^9
+ # ^10
+
+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
+
+== Alternation
+
+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,
+ 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)
+* <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.
+
+ " a b c".gsub(/ /, '_') #=> "____a_b_c"
+ " a b c".gsub(/\G /, '_') #=> "____a b c"
+
+ In methods like <tt>Regexp#match</tt> and <tt>String#match</tt> that take an (optional) offset, it matches where the search begins.
+
+ "hello, world".match(/,/, 3) #=> #<MatchData ",">
+ "hello, world".match(/\G,/, 3) #=> nil
+
+* <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
+
+* <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:
+
+ /ab\Kc/ =~ "abc" #=> 0
+ /(?<=ab)c/ =~ "abc" #=> 2
+
+ These match same string and <i>$&</i> equals <tt>"c"</tt>, while the
+ matched position is different.
+
+ As are the following two regexps:
+
+ /(a)\K(b)\Kc/
+ /(?<=(?<=(a))(b))c/
+
+If a pattern isn't anchored it can begin at any point in the string:
+
+ /real/.match("surrealist") #=> #<MatchData "real">
+
+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:
+
+ /\Areal/.match("surrealist") #=> nil
+
+The match below fails because although 'Demand' contains 'and', the pattern
+does not occur at a word boundary.
+
+ /\band/.match("Demand")
+
+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:
+
+ /\Band.+/.match("Supply and demand curve") #=> #<MatchData "and curve">
+
+The pattern below uses positive lookahead and positive lookbehind to match
+text appearing in <b></b> tags without including the tags in the match:
+
+ /(?<=<b>)\w+(?=<\/b>)/.match("Fortune favours the <b>bold</b>")
+ #=> #<MatchData "bold">
+
+== Options
+
+The end delimiter for a regexp can be followed by one or more single-letter
+options which control how the pattern can match.
+
+* <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
+
+<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:
+
+ /a(?i:b)c/.match('aBc') #=> #<MatchData "aBc">
+ /a(?-i:b)c/i.match('ABC') #=> nil
+
+Additionally, these options can also be toggled for the remainder of the
+pattern:
+
+ /a(?i)bc/.match('abC') #=> #<MatchData "abC">
+
+Options may also be used with <tt>Regexp.new</tt>:
+
+ 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
+
+ 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
+
+== Free-Spacing Mode and Comments
+
+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.
+
+A contrived pattern to match a number with optional decimal places:
+
+ 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">
+
+There are a number of strategies for matching whitespace:
+
+* 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>.
+
+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.
+
+Comments in regexp literals cannot include unescaped terminator
+characters.
+
+== Encoding
+
+Regular expressions are assumed to use the source encoding. This can be
+overridden with one of the following modifiers.
+
+* <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
+
+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.
+
+If a match between incompatible encodings is attempted an
+<tt>Encoding::CompatibilityError</tt> exception is raised.
+
+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>:
+
+ 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)
+
+== \Regexp Global Variables
+
+Pattern matching sets some global variables :
+
+* <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:
+
+ 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">
+
+ $& #=> "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]
+
+These global variables are thread-local and method-local variables.
+
+== Performance
+
+Certain pathological combinations of constructs can lead to abysmally bad
+performance.
+
+Consider a string of 25 <i>a</i>s, a <i>d</i>, 4 <i>a</i>s, and a
+<i>c</i>.
+
+ s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
+ #=> "aaaaaaaaaaaaaaaaaaaaaaaaadaaaac"
+
+The following patterns match instantly as you would expect:
+
+ /(b|a)/ =~ s #=> 0
+ /(b|a+)/ =~ s #=> 0
+ /(b|a+)*/ =~ s #=> 0
+
+However, the following pattern takes appreciably longer:
+
+ /(b|a+)*c/ =~ s #=> 26
+
+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:
+
+ (start = Time.now) && /(b|a+)*c/ =~ s && (Time.now - start)
+ #=> 24.702736882
+ (start = Time.now) && /(?>b|a+)*c/ =~ s && (Time.now - start)
+ #=> 0.000166571
+
+A similar case is typified by the following example, which takes
+approximately 60 seconds to execute for me:
+
+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:
+
+ Regexp.new('a?' * 29 + 'a' * 29) =~ 'a' * 29
+
+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.
+
+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.new('a{0,29}' + 'a' * 29) =~ 'a' * 29
+
+== Timeout
+
+There are two APIs to set timeout. One is Regexp.timeout=, which is
+process-global configuration of timeout for Regexp matching.
+
+ Regexp.timeout = 3
+ s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
+ /(b|a+)*c/ =~ s #=> This raises an exception in three seconds
+
+The other is timeout keyword of Regexp.new.
+
+ 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
+
+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 1fa916123b..0000000000
--- a/doc/reline/face.md
+++ /dev/null
@@ -1,111 +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"}}}
-```
-
-## 256-Color and TrueColor
-
-Reline will automatically detect if your terminal emulator supports truecolor with `ENV['COLORTERM] in 'truecolor' | '24bit'`. When this env is not set, Reline will fallback to 256-color.
-If your terminal emulator supports truecolor but does not set COLORTERM env, add this line to `.irbrc`.
-```ruby
-Reline::Face.force_truecolor
-```
diff --git a/doc/rjit/rjit.md b/doc/rjit/rjit.md
deleted file mode 100644
index 9e60e43ce3..0000000000
--- a/doc/rjit/rjit.md
+++ /dev/null
@@ -1,45 +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.
-
-## 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.
-
-### --rjit-dump-disasm
-
-This dumps all JIT code. You need to install libcapstone before configure and use `--enable-rjit=dev` 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/strftime_formatting.rdoc b/doc/strftime_formatting.rdoc
index 7694752a21..30a629bf68 100644
--- a/doc/strftime_formatting.rdoc
+++ b/doc/strftime_formatting.rdoc
@@ -1,4 +1,4 @@
-= Formats for Dates and Times
+== Formats for Dates and Times
Several Ruby time-related classes have instance method +strftime+,
which returns a formatted string representing all or part of a date or time:
@@ -32,9 +32,9 @@ It consists of:
Except for the leading percent character,
the only required part is the conversion specifier, so we begin with that.
-== Conversion Specifiers
+=== Conversion Specifiers
-=== \Date (Year, Month, Day)
+==== \Date (Year, Month, Day)
- <tt>%Y</tt> - Year including century, zero-padded:
@@ -87,7 +87,7 @@ the only required part is the conversion specifier, so we begin with that.
Time.new(2002, 1, 1).strftime('%j') # => "001"
Time.new(2002, 12, 31).strftime('%j') # => "365"
-=== \Time (Hour, Minute, Second, Subsecond)
+==== \Time (Hour, Minute, Second, Subsecond)
- <tt>%H</tt> - Hour of the day, in range (0..23), zero-padded:
@@ -152,7 +152,7 @@ the only required part is the conversion specifier, so we begin with that.
Time.now.strftime('%s') # => "1656505136"
-=== Timezone
+==== Timezone
- <tt>%z</tt> - Timezone as hour and minute offset from UTC:
@@ -162,7 +162,7 @@ the only required part is the conversion specifier, so we begin with that.
Time.now.strftime('%Z') # => "Central Daylight Time"
-=== Weekday
+==== Weekday
- <tt>%A</tt> - Full weekday name:
@@ -184,7 +184,7 @@ the only required part is the conversion specifier, so we begin with that.
t.strftime('%a') # => "Sun"
t.strftime('%w') # => "0"
-=== Week Number
+==== Week Number
- <tt>%U</tt> - Week number of the year, in range (0..53), zero-padded,
where each week begins on a Sunday:
@@ -200,7 +200,7 @@ the only required part is the conversion specifier, so we begin with that.
t.strftime('%a') # => "Sun"
t.strftime('%W') # => "25"
-=== Week Dates
+==== Week Dates
See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
@@ -223,7 +223,7 @@ See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
t0.strftime('%V') # => "52"
t1.strftime('%V') # => "01"
-=== Literals
+==== Literals
- <tt>%n</tt> - Newline character "\n":
@@ -237,7 +237,7 @@ See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
Time.now.strftime('%%') # => "%"
-=== Shorthand Conversion Specifiers
+==== Shorthand Conversion Specifiers
Each shorthand specifier here is shown with its corresponding
longhand specifier.
@@ -294,14 +294,14 @@ longhand specifier.
DateTime.now.strftime('%a %b %e %H:%M:%S %Z %Y')
# => "Wed Jun 29 08:32:18 -05:00 2022"
-== Flags
+=== Flags
Flags may affect certain formatting specifications.
Multiple flags may be given with a single conversion specified;
order does not matter.
-=== Padding Flags
+==== Padding Flags
- <tt>0</tt> - Pad with zeroes:
@@ -315,7 +315,7 @@ order does not matter.
Time.new(10).strftime('%-Y') # => "10"
-=== Casing Flags
+==== Casing Flags
- <tt>^</tt> - Upcase result:
@@ -328,7 +328,7 @@ order does not matter.
Time.now.strftime('%^p') # => "AM"
Time.now.strftime('%#p') # => "am"
-=== Timezone Flags
+==== Timezone Flags
- <tt>:</tt> - Put timezone as colon-separated hours and minutes:
@@ -338,7 +338,7 @@ order does not matter.
Time.now.strftime('%::z') # => "-05:00:00"
-== Width Specifiers
+=== Width Specifiers
The integer width specifier gives a minimum width for the returned string:
@@ -348,12 +348,12 @@ The integer width specifier gives a minimum width for the returned string:
Time.new(2002, 12).strftime('%10B') # => " December"
Time.new(2002, 12).strftime('%3B') # => "December" # Ignored if too small.
-= Specialized Format Strings
+== Specialized Format Strings
Here are a few specialized format strings,
each based on an external standard.
-== HTTP Format
+=== HTTP Format
The HTTP date format is based on
{RFC 2616}[https://datatracker.ietf.org/doc/html/rfc2616],
@@ -368,7 +368,7 @@ and treats dates in the format <tt>'%a, %d %b %Y %T GMT'</tt>:
Date._httpdate(httpdate)
# => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"GMT", :offset=>0}
-== RFC 3339 Format
+=== RFC 3339 Format
The RFC 3339 date format is based on
{RFC 3339}[https://datatracker.ietf.org/doc/html/rfc3339]:
@@ -382,7 +382,7 @@ The RFC 3339 date format is based on
Date._rfc3339(rfc3339)
# => {:year=>2001, :mon=>2, :mday=>3, :hour=>0, :min=>0, :sec=>0, :zone=>"+00:00", :offset=>0}
-== RFC 2822 Format
+=== RFC 2822 Format
The RFC 2822 date format is based on
{RFC 2822}[https://datatracker.ietf.org/doc/html/rfc2822],
@@ -397,7 +397,7 @@ and treats dates in the format <tt>'%a, %-d %b %Y %T %z'</tt>]:
Date._rfc2822(rfc2822)
# => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"+0000", :offset=>0}
-== JIS X 0301 Format
+=== JIS X 0301 Format
The JIS X 0301 format includes the
{Japanese era name}[https://en.wikipedia.org/wiki/Japanese_era_name],
@@ -412,7 +412,7 @@ with the first letter of the romanized era name prefixed:
# Return hash parsed from 0301-formatted string.
Date._jisx0301(jisx0301) # => {:year=>2001, :mon=>2, :mday=>3}
-== ISO 8601 Format Specifications
+=== ISO 8601 Format Specifications
This section shows format specifications that are compatible with
{ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601].
@@ -422,7 +422,7 @@ Examples in this section assume:
t = Time.now # => 2022-06-29 16:49:25.465246 -0500
-=== Dates
+==== Dates
See {ISO 8601 dates}[https://en.wikipedia.org/wiki/ISO_8601#Dates].
@@ -473,7 +473,7 @@ See {ISO 8601 dates}[https://en.wikipedia.org/wiki/ISO_8601#Dates].
t.strftime('%Y-%j') # => "2022-180"
-=== Times
+==== Times
See {ISO 8601 times}[https://en.wikipedia.org/wiki/ISO_8601#Times].
@@ -514,7 +514,7 @@ See {ISO 8601 times}[https://en.wikipedia.org/wiki/ISO_8601#Times].
- {Coordinated Universal Time (UTC)}[https://en.wikipedia.org/wiki/ISO_8601#Coordinated_Universal_Time_(UTC)].
- {Time offsets from UTC}[https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC].
-=== Combined \Date and \Time
+==== Combined \Date and \Time
See {ISO 8601 Combined date and time representations}[https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations].
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/string/new.rdoc b/doc/string/new.rdoc
index 1d44291f76..d955e61c87 100644
--- a/doc/string/new.rdoc
+++ b/doc/string/new.rdoc
@@ -46,10 +46,6 @@ which may in turn affect performance:
String.new(capacity: 1)
String.new('foo', capacity: 4096)
-Note that Ruby strings are null-terminated internally, so the internal
-buffer size will be one or more bytes larger than the requested capacity
-depending on the encoding.
-
The +string+, +encoding+, and +capacity+ arguments may all be used together:
String.new('hello', encoding: 'UTF-8', capacity: 25)
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/calling_methods.rdoc b/doc/syntax/calling_methods.rdoc
index 6cc8678450..da061dbfdb 100644
--- a/doc/syntax/calling_methods.rdoc
+++ b/doc/syntax/calling_methods.rdoc
@@ -322,6 +322,18 @@ Both are equivalent to:
my_method(1, 2, 3)
+If the method accepts keyword arguments, the splat operator will convert a
+hash at the end of the array into keyword arguments:
+
+ def my_method(a, b, c: 3)
+ end
+
+ arguments = [1, 2, { c: 4 }]
+ my_method(*arguments)
+
+Note that this behavior is currently deprecated and will emit a warning.
+This behavior will be removed in Ruby 3.0.
+
You may also use the <code>**</code> (described next) to convert a Hash into
keyword arguments.
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..5e10e6a140 100644
--- a/doc/syntax/literals.rdoc
+++ b/doc/syntax/literals.rdoc
@@ -277,12 +277,6 @@ the content. Note that empty lines and lines consisting solely of literal tabs
and spaces will be ignored for the purposes of determining indentation, but
escaped tabs and spaces are considered non-indentation characters.
-For the purpose of measuring an indentation, a horizontal tab is regarded as a
-sequence of one to eight spaces such that the column position corresponding to
-its end is a multiple of eight. The amount to be removed is counted in terms
-of the number of spaces. If the boundary appears in the middle of a tab, that
-tab is not removed.
-
A heredoc allows interpolation and escaped characters. You may disable
interpolation and escaping by surrounding the opening identifier with single
quotes:
@@ -414,9 +408,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 +517,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 236b3413b5..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 occurrence of a
-falsey expression. The expression that defines the result is the last one
-executed, whether it be the final expression, or the first occurrence 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/timezones.rdoc b/doc/timezones.rdoc
new file mode 100644
index 0000000000..c3aae88fde
--- /dev/null
+++ b/doc/timezones.rdoc
@@ -0,0 +1,108 @@
+== Timezones
+
+=== Timezone Specifiers
+
+Certain \Time methods accept arguments that specify timezones:
+
+- Time.at: keyword argument +in:+.
+- Time.new: positional argument +zone+ or keyword argument +in:+.
+- Time.now: keyword argument +in:+.
+- Time#getlocal: positional argument +zone+.
+- Time#localtime: positional argument +zone+.
+
+The value given with any of these must be one of the following
+(each detailed below):
+
+- {Hours/minutes offset}[rdoc-ref:timezones.rdoc@Hours-2FMinutes+Offsets].
+- {Single-letter offset}[rdoc-ref:timezones.rdoc@Single-Letter+Offsets].
+- {Integer offset}[rdoc-ref:timezones.rdoc@Integer+Offsets].
+- {Timezone object}[rdoc-ref:timezones.rdoc@Timezone+Objects].
+
+==== Hours/Minutes Offsets
+
+The zone value may be a string offset from UTC
+in the form <tt>'+HH:MM'</tt> or <tt>'-HH:MM'</tt>,
+where:
+
+- +HH+ is the 2-digit hour in the range <tt>0..23</tt>.
+- +MM+ is the 2-digit minute in the range <tt>0..59</tt>.
+
+Examples:
+
+ t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
+ Time.at(t, in: '-23:59') # => 1999-12-31 20:16:01 -2359
+ Time.at(t, in: '+23:59') # => 2000-01-02 20:14:01 +2359
+
+==== Single-Letter Offsets
+
+The zone value may be a letter in the range <tt>'A'..'I'</tt>
+or <tt>'K'..'Z'</tt>;
+see {List of military time zones}[https://en.wikipedia.org/wiki/List_of_military_time_zones]:
+
+ t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
+ Time.at(t, in: 'A') # => 2000-01-01 21:15:01 +0100
+ Time.at(t, in: 'I') # => 2000-01-02 05:15:01 +0900
+ Time.at(t, in: 'K') # => 2000-01-02 06:15:01 +1000
+ Time.at(t, in: 'Y') # => 2000-01-01 08:15:01 -1200
+ Time.at(t, in: 'Z') # => 2000-01-01 20:15:01 UTC
+
+==== \Integer Offsets
+
+The zone value may be an integer number of seconds
+in the range <tt>-86399..86399</tt>:
+
+ t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
+ Time.at(t, in: -86399) # => 1999-12-31 20:15:02 -235959
+ Time.at(t, in: 86399) # => 2000-01-02 20:15:00 +235959
+
+==== Timezone Objects
+
+In most cases, the zone value may be an object
+responding to certain timezone methods.
+
+\Exceptions (timezone object not allowed):
+
+- Time.new with positional argument +zone+.
+- Time.now with keyword argument +in:+.
+
+The timezone methods are:
+
+- +local_to_utc+:
+
+ - Called when Time.new is invoked with +tz+
+ as the value of positional argument +zone+ or keyword argument +in:+.
+ - Argument: a <tt>Time::tm</tt> object.
+ - Returns: a \Time-like object in the UTC timezone.
+
+- +utc_to_local+:
+
+ - Called when Time.at or Time.now is invoked with +tz+
+ as the value for keyword argument +in:+,
+ and when Time#getlocal or Time#localtime is called with +tz+
+ as the value for positional argument +zone+.
+ - Argument: a <tt>Time::tm</tt> object.
+ - Returns: a \Time-like object in the local timezone.
+
+A custom timezone class may have these instance methods,
+which will be called if defined:
+
+- +abbr+:
+
+ - Called when Time#strftime is invoked with a format involving <tt>%Z</tt>.
+ - Argument: a <tt>Time::tm</tt> object.
+ - Returns: a string abbreviation for the timezone name.
+
+- +dst?+:
+
+ - Called when Time.at or Time.now is invoked with +tz+
+ as the value for keyword argument +in:+,
+ and when Time#getlocal or Time#localtime is called with +tz+
+ as the value for positional argument +zone+.
+ - Argument: a <tt>Time::tm</tt> object.
+ - Returns: whether the time is daylight saving time.
+
+- +name+:
+
+ - Called when <tt>Marshal.dump(t) is invoked
+ - Argument: none.
+ - Returns: the string name of the timezone.
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 e6446e3ed1..0ab6b99ded 100644
--- a/doc/yjit/yjit.md
+++ b/doc/yjit/yjit.md
@@ -4,27 +4,24 @@
</a>
</p>
+
YJIT - Yet Another Ruby JIT
===========================
YJIT is a lightweight, minimalistic Ruby JIT built inside CRuby.
-It lazily compiles code using a Basic Block Versioning (BBV) architecture.
-YJIT is currently supported for macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs.
+It lazily compiles code using a Basic Block Versioning (BBV) architecture. The target use case is that of servers running
+Ruby on Rails, an area where MJIT has not yet managed to deliver speedups.
+YJIT is currently supported for macOS and Linux on x86-64 and arm64/aarch64 CPUs.
This project is open source and falls under the same license as CRuby.
<p align="center"><b>
If you're using YJIT in production, please
<a href="mailto:maxime.chevalierboisvert@shopify.com">share your success stories with us!</a>
-</b></p>
+ </b></p>
If you wish to learn more about the approach taken, here are some conference talks and publications:
-- RubyKaigi 2023 keynote: [Optimizing YJIT’s Performance, from Inception to Production](https://www.youtube.com/watch?v=X0JRhh8w_4I)
-- RubyKaigi 2023 keynote: [Fitting Rust YJIT into CRuby](https://www.youtube.com/watch?v=GI7vvAgP_Qs)
-- RubyKaigi 2022 keynote: [Stories from developing YJIT](https://www.youtube.com/watch?v=EMchdR9C8XM)
-- 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,31 +29,32 @@ 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}
}
```
## Current Limitations
-YJIT may not be suitable for certain applications. It currently only supports macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs. YJIT will use more memory than the Ruby interpreter because the JIT compiler needs to generate machine code in memory and maintain additional state information.
-You can change how much executable memory is allocated using [YJIT's command-line options](#command-line-options).
+YJIT may not be suitable for certain applications. It currently only supports macOS and Linux on x86-64 and arm64/aarch64 CPUs. YJIT will use more memory than the Ruby interpreter because the JIT compiler needs to generate machine code in memory and maintain additional state
+information.
+You can change how much executable memory is allocated using [YJIT's command-line options](#command-line-options). There is a slight performance tradeoff because allocating less executable memory could result in the generated machine code being collected more often.
## Installation
@@ -82,43 +80,34 @@ git clone https://github.com/ruby/ruby yjit
cd yjit
```
-The YJIT `ruby` binary can be built with either GCC or Clang. It can be built either in dev (debug) mode or in release mode. For maximum performance, compile YJIT in release mode with GCC. More detailed build instructions are provided in the [Ruby README](https://github.com/ruby/ruby#how-to-build).
+The YJIT `ruby` binary can be built with either GCC or Clang. It can be built either in dev (debug) mode or in release mode. For maximum performance, compile YJIT in release mode with GCC. More detailed build instructions are provided in the [Ruby README](https://github.com/ruby/ruby#how-to-compile-and-install).
```sh
# Configure in release mode for maximum performance, build and install
./autogen.sh
./configure --enable-yjit --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc
-make -j && make install
+make -j install
```
or
```sh
-# Configure in lower-performance dev (debug) mode for development, build and install
+# Configure in dev (debug) mode for development, build and install
./autogen.sh
./configure --enable-yjit=dev --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc
-make -j && make install
-```
-
-Dev mode includes extended YJIT statistics, but can be slow. For only statistics you can configure in stats mode:
-
-```sh
-# Configure in extended-stats mode without slow runtime checks, build and install
-./autogen.sh
-./configure --enable-yjit=stats --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc
-make -j && make install
+make -j install
```
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
./configure --enable-yjit=dev --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc --with-opt-dir="$(brew --prefix openssl):$(brew --prefix readline):$(brew --prefix libyaml)"
-make -j && make install
+make -j install
```
Typically configure will choose the default C compiler. To specify the C compiler, use
@@ -165,126 +154,49 @@ The machine code generated for a given method can be printed by adding `puts Rub
YJIT supports all command-line options supported by upstream CRuby, but also adds a few YJIT-specific options:
- `--yjit`: enable YJIT (disabled by default)
-- `--yjit-exec-mem-size=N`: size of the executable memory block to allocate, in MiB (default 48 MiB)
-- `--yjit-call-threshold=N`: number of calls after which YJIT begins to compile a function.
- It defaults to 30, and it's then increased to 120 when the number of ISEQs in the process reaches 40,000.
-- `--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 200K)
-- `--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-disable`: disable YJIT despite other `--yjit*` flags for lazily enabling it with `RubyVM::YJIT.enable`
-- `--yjit-code-gc`: enable code GC (disabled by default as of Ruby 3.3).
- It will cause all machine code to be discarded when the executable memory size limit is hit, meaning JIT compilation will then start over.
- This can allow you to use a lower executable memory size limit, but may cause a slight drop in performance when the limit is hit.
-- `--yjit-perf`: enable frame pointers and profiling with the `perf` tool
-- `--yjit-trace-exits`: produce a Marshal dump of backtraces from specific exits. Automatically enables `--yjit-stats`
-- `--yjit-trace-exits-sample-rate=N`: trace exit locations only every Nth occurrence
+- `--yjit-call-threshold=N`: number of calls after which YJIT begins to compile a function (default 30)
+- `--yjit-exec-mem-size=N`: size of the executable memory block to allocate, in MiB (default 128 MiB)
+- `--yjit-stats`: produce statistics after the execution of a program
+- `--yjit-trace-exits`: produce a Marshal dump of backtraces from specific exits. Automatically enables `--yjit-stats` (must configure and build with `--enable-yjit=stats` to use this)
+- `--yjit-max-versions=N`: maximum number of versions to generate per basic block (default 4)
+- `--yjit-greedy-versioning`: greedy versioning mode (disabled by default, may increase code size)
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 also enable YJIT at run-time using `RubyVM::YJIT.enable`. This can allow you to enable YJIT after your application is done
-booting, which makes it possible to avoid compiling any initialization code.
-
-You can verify that YJIT is enabled using `RubyVM::YJIT.enabled?` or by checking that `ruby --yjit -v` includes the string `+YJIT`:
-
-```sh
-ruby --yjit -v
-ruby 3.3.0dev (2023-01-31T15:11:10Z master 2a0bf269c9) +YJIT dev [x86_64-darwin22]
-
-ruby --yjit -e "p RubyVM::YJIT.enabled?"
-true
-
-ruby -e "RubyVM::YJIT.enable; p RubyVM::YJIT.enabled?"
-true
-```
-
### 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.
-
-## Performance Tips for Production Deployments
-
-While YJIT options default to what we think would work well for most workloads,
-they might not necessarily be the best configuration for your application.
-This section covers tips on improving YJIT performance in case YJIT does not
-speed up your application in production.
-
-### Increasing --yjit-exec-mem-size
-
-When JIT code size (`RubyVM::YJIT.runtime_stats[:code_region_size]`) reaches this value,
-YJIT stops compiling new code. Increasing the executable memory size means more code
-can be optimized by YJIT, at the cost of more memory usage.
-
-If you start Ruby with `--yjit-stats`, e.g. using an environment variable `RUBYOPT=--yjit-stats`,
-`RubyVM::YJIT.runtime_stats[:ratio_in_yjit]` shows the ratio of YJIT-executed instructions in %.
-Ideally, `ratio_in_yjit` should be as large as 99%, and increasing `--yjit-exec-mem-size` often
-helps improving `ratio_in_yjit`.
-
-### Running workers as long as possible
+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.
-It's helpful to call the same code as many times as possible before a process restarts.
-If a process is killed too frequently, the time taken for compiling methods may outweigh
-the speedup obtained by compiling them.
+### Performance Tips
-You should monitor the number of requests each process has served.
-If you're periodically killing worker processes, e.g. with `unicorn-worker-killer` or `puma_worker_killer`,
-you may want to reduce the killing frequency or increase the limit.
+This section contains tips on writing Ruby code that will run as fast as possible on YJIT. Some of this advice is based on current limitations of YJIT, while other advice is broadly applicable. It probably won't be practical to apply these tips everywhere in your codebase, but you can profile your code using a tool such as [stackprof](https://github.com/tmm1/stackprof) and refactor the specific methods that make up the largest fractions of the execution time.
-## Reducing YJIT Memory Usage
-
-YJIT allocates memory for JIT code and metadata. Enabling YJIT generally results in more memory usage.
-This section goes over tips on minimizing YJIT memory usage in case it uses more than your capacity.
-
-### Decreasing --yjit-exec-mem-size
-
-The `--yjit-exec-mem-size` option specifies the JIT code size, but YJIT also uses memory for its metadata,
-which often consumes more memory than JIT code. Generally, YJIT adds memory overhead by roughly
-3-4x of `--yjit-exec-mem-size` in production as of Ruby 3.3. You should multiply that by the number
-of worker processes to estimate the worst case memory overhead.
-
-`--yjit-exec-mem-size=48` is the default since Ruby 3.3.1,
-but smaller values like 32 MiB might make sense for your application.
-While doing so, you may want to monitor `RubyVM::YJIT.runtime_stats[:ratio_in_yjit]` as explained above.
-
-### Enabling YJIT lazily
-
-If you enable YJIT by `--yjit` options or `RUBY_YJIT_ENABLE=1`, YJIT may compile code that is
-used only during the application boot. `RubyVM::YJIT.enable` allows you to enable YJIT from Ruby code,
-and you can call this after your application is initialized, e.g. on Unicorn's `after_fork` hook.
-If you use any YJIT options (`--yjit-*`), YJIT will start at boot by default, but `--yjit-disable`
-allows you to start Ruby with the YJIT-disabled mode while passing YJIT tuning options.
-
-## Code Optimization Tips
-
-This section contains tips on writing Ruby code that will run as fast as possible on YJIT. Some of this advice is based on current limitations of YJIT, while other advice is broadly applicable. It probably won't be practical to apply these tips everywhere in your codebase. You should ideally start by profiling your application using a tool such as [stackprof](https://github.com/tmm1/stackprof) so that you can determine which methods make up most of the execution time. You can then refactor the specific methods that make up the largest fractions of the execution time. We do not recommend modifying your entire codebase based on the current limitations of YJIT.
-
-- Avoid using `OpenStruct`
+- Use exceptions for error recovery only, not as part of normal control-flow
- Avoid redefining basic integer operations (i.e. +, -, <, >, etc.)
- Avoid redefining the meaning of `nil`, equality, etc.
- Avoid allocating objects in the hot parts of your code
+- Use while loops if you can, instead of `integer.times`
- Minimize layers of indirection
- Avoid classes that wrap objects if you can
- - Avoid methods that just call another method, trivial one-liner methods
+ - Avoid methods that just call another method, trivial one liner methods
+- CRuby method calls are costly. Favor larger methods over smaller methods.
- Try to write code so that the same variables always have the same type
-- Use `while` loops if you can, instead of C methods like `Array#each`
- - This is not idiomatic Ruby, but could help in hot methods
-- CRuby method calls are costly. Avoid things such as methods that only return a value from a hash or return a constant.
You can also use the `--yjit-stats` command-line option to see which bytecodes cause YJIT to exit, and refactor your code to avoid using these instructions in the hottest methods of your code.
### Other Statistics
-If you run `ruby` with `--yjit-stats`, YJIT will track and return performance statistics in `RubyVM::YJIT.runtime_stats`.
+If you compile Ruby with `RUBY_DEBUG` and/or `YJIT_STATS` defined and run with `--yjit --yjit-stats`, YJIT will track and return performance statistics in `RubyVM::YJIT.runtime_stats`.
```rb
-$ RUBYOPT="--yjit-stats" irb
+$ RUBYOPT="--yjit --yjit-stats" irb
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,
@@ -293,38 +205,29 @@ irb(main):001:0> RubyVM::YJIT.runtime_stats
Some of the counters include:
-* :yjit_insns_count - 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
-* :vm_insns_count - number of instructions executed by the Ruby interpreter
-* :compiled_iseq_count - number of bytecode sequences compiled
-* :inline_code_size - size in bytes of compiled YJIT blocks
-* :outline_code_size - size in bytes of YJIT error-handling compiled code
-* :side_exit_count - number of side exits taken at runtime
-* :total_exit_count - number of exits, including side exits, taken at runtime
-* :avg_len_in_yjit - avg. number of instructions in compiled blocks before exiting to interpreter
-
-Counters starting with "exit_" show reasons for YJIT code taking a side exit (return to the interpreter.)
+: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
+:vm_insns_count - number of instructions executed by the Ruby interpreter
+:compiled_iseq_count - number of bytecode sequences compiled
-Performance counter names are not guaranteed to remain the same between Ruby versions. If you're curious what each counter means,
-it's usually best to search the source code for it &mdash; but it may change in a later Ruby version.
+Counters starting with "exit_" show reasons for YJIT code taking a side exit (return to the interpreter.) See yjit_hacking.md for more details.
-The printed text after a `--yjit-stats` run includes other information that may be named differently than the information in `RubyVM::YJIT.runtime_stats`.
+Performance counter names are not guaranteed to remain the same between Ruby versions. If you're curious what one does, it's usually best to search the source code for it &mdash; but it may change in a later Ruby version.
## Contributing
-We welcome open source contributions. You should feel free to open new issues to report bugs or just to ask questions.
+We welcome open source contributors. You should feel free to open new issues to report bugs or just to ask questions.
Suggestions on how to make this readme file more helpful for new contributors are most welcome.
Bug fixes and bug reports are very valuable to us. If you find a bug in YJIT, it's very possible be that nobody has reported it before,
or that we don't have a good reproduction for it, so please open an issue and provide as much information as you can about your configuration and a description of how you encountered the problem. List the commands you used to run YJIT so that we can easily reproduce the issue on our end and investigate it. If you are able to produce a small program reproducing the error to help us track it down, that is very much appreciated as well.
-If you would like to contribute a large patch to YJIT, we suggest opening an issue or a discussion on the [Shopify/ruby repository](https://github.com/Shopify/ruby/issues) so that
+If you would like to contribute a large patch to YJIT, we suggest opening an issue or a discussion on this repository so that
we can have an active discussion. A common problem is that sometimes people submit large pull requests to open source projects
without prior communication, and we have to reject them because the work they implemented does not fit within the design of the
-project. We want to save you time and frustration, so please reach out so we can have a productive discussion as to how
-you can contribute patches we will want to merge into YJIT.
+project. We want to save you time and frustration, so please reach out and we can have a productive discussion as to how
+you can contribute things we will want to merge into YJIT.
### Source Code Organization
@@ -337,8 +240,10 @@ The YJIT source code is divided between:
- `yjit/src/core.rb`: basic block versioning logic, core structure of YJIT
- `yjit/src/stats.rs`: gathering of run-time statistics
- `yjit/src/options.rs`: handling of command-line options
-- `yjit/src/cruby.rs`: C bindings manually exposed to the Rust codebase
- `yjit/bindgen/src/main.rs`: C bindings exposed to the Rust codebase through bindgen
+- `yjit/src/cruby.rs`: C bindings manually exposed to the Rust codebase
+- `misc/test_yjit_asm.sh`: script to compile and run the in-memory assembler tests
+- `misc/yjit_asm_tests.c`: tests for the in-memory assembler
The core of CRuby's interpreter logic is found in:
- `insns.def`: defines Ruby's bytecode instructions (gets compiled into `vm.inc`)
@@ -361,12 +266,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:
@@ -446,30 +350,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 9d0c367134..dd8ca1b528 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@
+INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(top_srcdir)
DEFS = @DEFS@
CPPFLAGS = @CPPFLAGS@ -DONIG_ENC_REGISTER=rb_enc_register
LDFLAGS = @LDFLAGS@
diff --git a/enc/cesu_8.c b/enc/cesu_8.c
index 75f62df280..decbb928f4 100644
--- a/enc/cesu_8.c
+++ b/enc/cesu_8.c
@@ -42,8 +42,6 @@
#define VALID_CODE_LIMIT 0x0010ffff
#define utf8_islead(c) ((UChar )((c) & 0xc0) != 0x80)
-#define utf16_is_high_surrogate(v) ((v >> 10) == 0x36)
-#define utf16_is_low_surrogate(v) ((v >> 10) == 0x37)
static const int EncLen_CESU8[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -285,12 +283,6 @@ is_mbc_newline(const UChar* p, const UChar* end, OnigEncoding enc)
return 0;
}
-static int
-utf8_decode_3byte_sequence(const UChar* p)
-{
- return ((p[0] & 0xF) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f);
-}
-
static OnigCodePoint
mbc_to_code(const UChar* p, const UChar* end, OnigEncoding enc)
{
@@ -303,11 +295,11 @@ mbc_to_code(const UChar* p, const UChar* end, OnigEncoding enc)
case 2:
return ((p[0] & 0x1F) << 6) | (p[1] & 0x3f);
case 3:
- return utf8_decode_3byte_sequence(p);
+ return ((p[0] & 0xF) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f);
case 6:
{
- int high = utf8_decode_3byte_sequence(p);
- int low = utf8_decode_3byte_sequence(p + 3);
+ int high = ((p[0] & 0xF) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f);
+ int low = ((p[3] & 0xF) << 12) | ((p[4] & 0x3f) << 6) | (p[5] & 0x3f);
return ((high & 0x03ff) << 10) + (low & 0x03ff) + 0x10000;
}
}
@@ -418,6 +410,7 @@ get_ctype_code_range(OnigCtype ctype, OnigCodePoint *sb_out,
return onigenc_unicode_ctype_code_range(ctype, ranges);
}
+
static UChar*
left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, OnigEncoding enc ARG_UNUSED)
{
@@ -427,14 +420,6 @@ left_adjust_char_head(const UChar* start, const UChar* s, const UChar* end, Onig
p = s;
while (!utf8_islead(*p) && p > start) p--;
-
- if (p > start && s - p == 2 && utf16_is_low_surrogate(utf8_decode_3byte_sequence(p))) {
- const UChar *p_surrogate_pair = p - 1;
- while (!utf8_islead(*p_surrogate_pair) && p_surrogate_pair > start) p_surrogate_pair--;
- if (p - p_surrogate_pair == 3 && utf16_is_high_surrogate(utf8_decode_3byte_sequence(p_surrogate_pair))) {
- return (UChar* )p_surrogate_pair;
- }
- }
return (UChar* )p;
}
diff --git a/enc/depend b/enc/depend
index 12ddbc223a..60c5a3ebb2 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
@@ -6973,7 +7019,6 @@ 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/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 +7078,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 +7109,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 +7178,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 +7237,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 +7268,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 +7337,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 +7396,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 +7427,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 +7496,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 +7555,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 +7586,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 +7655,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 +7714,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 +7745,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 +7813,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 +7872,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 +7903,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 +7972,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 +8031,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 +8062,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 +8131,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 +8190,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 +8221,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 +8291,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 +8350,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 +8381,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 +8450,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 +8509,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 +8540,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 +8612,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 +8671,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 +8702,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 +8774,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 +8842,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 +8873,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 +8946,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 +9005,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 +9036,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 +9108,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 +9167,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 +9198,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 +9270,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 +9329,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 +9360,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 +9432,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 +9491,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 +9522,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 +9594,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 +9662,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 +9693,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 +9766,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 +9825,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 +9856,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 +9927,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 +9986,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 +10017,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 +10089,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 +10148,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 +10179,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 +10250,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 +10309,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 +10340,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 +10412,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 +10471,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 +10502,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 +10574,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 +10633,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 +10664,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 +10738,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 +10797,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 +10828,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 3613fcc9f0..39a47f2b8c 100644
--- a/encoding.c
+++ b/encoding.c
@@ -71,24 +71,6 @@ static struct enc_table {
st_table *names;
} global_enc_table;
-static int
-enc_names_free_i(st_data_t name, st_data_t idx, st_data_t args)
-{
- ruby_xfree((void *)name);
- return ST_DELETE;
-}
-
-void
-rb_free_global_enc_table(void)
-{
- for (size_t i = 0; i < ENCODING_LIST_CAPA; i++) {
- xfree((void *)global_enc_table.list[i].enc);
- }
-
- st_foreach(global_enc_table.names, enc_names_free_i, (st_data_t)0);
- st_free_table(global_enc_table.names);
-}
-
static rb_encoding *global_enc_ascii,
*global_enc_utf_8,
*global_enc_us_ascii;
@@ -120,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)
@@ -523,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)
{
@@ -1291,7 +1304,7 @@ enc_names_i(st_data_t name, st_data_t idx, st_data_t args)
VALUE *arg = (VALUE *)args;
if ((int)idx == (int)arg[0]) {
- VALUE str = rb_interned_str_cstr((char *)name);
+ VALUE str = rb_fstring_cstr((char *)name);
rb_ary_push(arg[1], str);
}
return ST_CONTINUE;
@@ -1543,14 +1556,7 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
if (NIL_P(encoding)) {
def->index = -1;
def->enc = 0;
- 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_insert(enc_table->names, (st_data_t)strdup(name),
(st_data_t)UNSPECIFIED_ENCODING);
}
else {
@@ -1788,7 +1794,7 @@ static int
rb_enc_name_list_i(st_data_t name, st_data_t idx, st_data_t arg)
{
VALUE ary = (VALUE)arg;
- VALUE str = rb_interned_str_cstr((char *)name);
+ VALUE str = rb_fstring_cstr((char *)name);
rb_ary_push(ary, str);
return ST_CONTINUE;
}
@@ -1833,7 +1839,7 @@ rb_enc_aliases_enc_i(st_data_t name, st_data_t orig, st_data_t arg)
str = rb_fstring_cstr(rb_enc_name(enc));
rb_ary_store(ary, idx, str);
}
- key = rb_interned_str_cstr((char *)name);
+ key = rb_fstring_cstr((char *)name);
rb_hash_aset(aliases, key, str);
return ST_CONTINUE;
}
@@ -1908,6 +1914,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 cd48e80866..391de0b337 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:
+ case T_FLOAT: sum_iter_Kahan_Babuska(i, memo); return;
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 d2819e4049..f6b3aae1f7 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:
*
@@ -169,10 +164,7 @@ static VALUE sym_each, sym_cycle, sym_yield;
static VALUE lazy_use_super_method;
-extern ID ruby_static_id_cause;
-
#define id_call idCall
-#define id_cause ruby_static_id_cause
#define id_each idEach
#define id_eqq idEqq
#define id_initialize idInitialize
@@ -195,19 +187,6 @@ struct enumerator {
int kw_splat;
};
-RUBY_REFERENCES(enumerator_refs) = {
- RUBY_REF_EDGE(struct enumerator, obj),
- RUBY_REF_EDGE(struct enumerator, args),
- RUBY_REF_EDGE(struct enumerator, fib),
- RUBY_REF_EDGE(struct enumerator, dst),
- RUBY_REF_EDGE(struct enumerator, lookahead),
- RUBY_REF_EDGE(struct enumerator, feedvalue),
- RUBY_REF_EDGE(struct enumerator, stop_exc),
- RUBY_REF_EDGE(struct enumerator, size),
- RUBY_REF_EDGE(struct enumerator, procs),
- RUBY_REF_END
-};
-
static VALUE rb_cGenerator, rb_cYielder, rb_cEnumProducer;
struct generator {
@@ -257,15 +236,56 @@ 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
+enumerator_memsize(const void *p)
+{
+ return sizeof(struct enumerator);
+}
+
static const rb_data_type_t enumerator_data_type = {
"enumerator",
{
- RUBY_REFS_LIST_PTR(enumerator_refs),
- RUBY_TYPED_DEFAULT_FREE,
- NULL, // Nothing allocated externally, so don't need a memsize function
- NULL,
+ enumerator_mark,
+ enumerator_free,
+ enumerator_memsize,
+ enumerator_compact,
},
- 0, NULL, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct enumerator *
@@ -296,15 +316,22 @@ proc_entry_compact(void *p)
ptr->memo = rb_gc_location(ptr->memo);
}
+#define proc_entry_free RUBY_TYPED_DEFAULT_FREE
+
+static size_t
+proc_entry_memsize(const void *p)
+{
+ return p ? sizeof(struct proc_entry) : 0;
+}
+
static const rb_data_type_t proc_entry_data_type = {
"proc_entry",
{
proc_entry_mark,
- RUBY_TYPED_DEFAULT_FREE,
- NULL, // Nothing allocated externally, so don't need a memsize function
+ proc_entry_free,
+ proc_entry_memsize,
proc_entry_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
static struct proc_entry *
@@ -389,7 +416,7 @@ obj_to_enum(int argc, VALUE *argv, VALUE obj)
}
enumerator = rb_enumeratorize_with_size(obj, meth, argc, argv, 0);
if (rb_block_given_p()) {
- RB_OBJ_WRITE(enumerator, &enumerator_ptr(enumerator)->size, rb_block_proc());
+ enumerator_ptr(enumerator)->size = rb_block_proc();
}
return enumerator;
}
@@ -418,15 +445,15 @@ enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, const VALUE *ar
rb_raise(rb_eArgError, "unallocated enumerator");
}
- RB_OBJ_WRITE(enum_obj, &ptr->obj, obj);
+ ptr->obj = obj;
ptr->meth = rb_to_id(meth);
- if (argc) RB_OBJ_WRITE(enum_obj, &ptr->args, rb_ary_new4(argc, argv));
+ if (argc) ptr->args = rb_ary_new4(argc, argv);
ptr->fib = 0;
ptr->dst = Qnil;
ptr->lookahead = Qundef;
ptr->feedvalue = Qundef;
ptr->stop_exc = Qfalse;
- RB_OBJ_WRITE(enum_obj, &ptr->size, size);
+ ptr->size = size;
ptr->size_fn = size_fn;
ptr->kw_splat = kw_splat;
@@ -505,13 +532,13 @@ enumerator_init_copy(VALUE obj, VALUE orig)
rb_raise(rb_eArgError, "unallocated enumerator");
}
- RB_OBJ_WRITE(obj, &ptr1->obj, ptr0->obj);
- RB_OBJ_WRITE(obj, &ptr1->meth, ptr0->meth);
- RB_OBJ_WRITE(obj, &ptr1->args, ptr0->args);
+ ptr1->obj = ptr0->obj;
+ ptr1->meth = ptr0->meth;
+ ptr1->args = ptr0->args;
ptr1->fib = 0;
ptr1->lookahead = Qundef;
ptr1->feedvalue = Qundef;
- RB_OBJ_WRITE(obj, &ptr1->size, ptr0->size);
+ ptr1->size = ptr0->size;
ptr1->size_fn = ptr0->size_fn;
return obj;
@@ -559,17 +586,11 @@ enumerator_block_call(VALUE obj, rb_block_call_func *func, VALUE arg)
const struct enumerator *e = enumerator_ptr(obj);
ID meth = e->meth;
- VALUE args = e->args;
- if (args) {
- argc = RARRAY_LENINT(args);
- argv = RARRAY_CONST_PTR(args);
+ if (e->args) {
+ argc = RARRAY_LENINT(e->args);
+ argv = RARRAY_CONST_PTR(e->args);
}
-
- VALUE ret = rb_block_call_kw(e->obj, meth, argc, argv, func, arg, e->kw_splat);
-
- RB_GC_GUARD(args);
-
- return ret;
+ return rb_block_call_kw(e->obj, meth, argc, argv, func, arg, e->kw_splat);
}
/*
@@ -626,7 +647,7 @@ enumerator_each(int argc, VALUE *argv, VALUE obj)
else {
args = rb_ary_new4(argc, argv);
}
- RB_OBJ_WRITE(obj, &e->args, args);
+ e->args = args;
e->size = Qnil;
e->size_fn = 0;
}
@@ -767,7 +788,7 @@ next_i(RB_BLOCK_CALL_FUNC_ARGLIST(_, obj))
VALUE result;
result = rb_block_call(obj, id_each, 0, 0, next_ii, obj);
- RB_OBJ_WRITE(obj, &e->stop_exc, rb_exc_new2(rb_eStopIteration, "iteration reached an end"));
+ e->stop_exc = rb_exc_new2(rb_eStopIteration, "iteration reached an end");
rb_ivar_set(e->stop_exc, id_result, result);
return rb_fiber_yield(1, &nil);
}
@@ -776,8 +797,8 @@ static void
next_init(VALUE obj, struct enumerator *e)
{
VALUE curr = rb_fiber_current();
- RB_OBJ_WRITE(obj, &e->dst, curr);
- RB_OBJ_WRITE(obj, &e->fib, rb_fiber_new(next_i, obj));
+ e->dst = curr;
+ e->fib = rb_fiber_new(next_i, obj);
e->lookahead = Qundef;
}
@@ -786,16 +807,8 @@ get_next_values(VALUE obj, struct enumerator *e)
{
VALUE curr, vs;
- if (e->stop_exc) {
- VALUE exc = e->stop_exc;
- VALUE result = rb_attr_get(exc, id_result);
- VALUE mesg = rb_attr_get(exc, idMesg);
- if (!NIL_P(mesg)) mesg = rb_str_dup(mesg);
- VALUE stop_exc = rb_exc_new_str(rb_eStopIteration, mesg);
- rb_ivar_set(stop_exc, id_cause, exc);
- rb_ivar_set(stop_exc, id_result, result);
- rb_exc_raise(stop_exc);
- }
+ if (e->stop_exc)
+ rb_exc_raise(e->stop_exc);
curr = rb_fiber_current();
@@ -865,8 +878,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;
@@ -928,12 +939,9 @@ enumerator_peek_values(VALUE obj)
{
struct enumerator *e = enumerator_ptr(obj);
- rb_check_frozen(obj);
-
if (UNDEF_P(e->lookahead)) {
- RB_OBJ_WRITE(obj, &e->lookahead, get_next_values(obj, e));
+ e->lookahead = get_next_values(obj, e);
}
-
return e->lookahead;
}
@@ -1055,12 +1063,10 @@ 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");
}
- RB_OBJ_WRITE(obj, &e->feedvalue, v);
+ e->feedvalue = v;
return Qnil;
}
@@ -1079,8 +1085,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;
@@ -1294,15 +1298,23 @@ yielder_compact(void *p)
ptr->proc = rb_gc_location(ptr->proc);
}
+#define yielder_free RUBY_TYPED_DEFAULT_FREE
+
+static size_t
+yielder_memsize(const void *p)
+{
+ return sizeof(struct yielder);
+}
+
static const rb_data_type_t yielder_data_type = {
"yielder",
{
yielder_mark,
- RUBY_TYPED_DEFAULT_FREE,
- NULL,
+ yielder_free,
+ yielder_memsize,
yielder_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct yielder *
@@ -1341,7 +1353,7 @@ yielder_init(VALUE obj, VALUE proc)
rb_raise(rb_eArgError, "unallocated yielder");
}
- RB_OBJ_WRITE(obj, &ptr->proc, proc);
+ ptr->proc = proc;
return obj;
}
@@ -1426,15 +1438,23 @@ generator_compact(void *p)
ptr->obj = rb_gc_location(ptr->obj);
}
+#define generator_free RUBY_TYPED_DEFAULT_FREE
+
+static size_t
+generator_memsize(const void *p)
+{
+ return sizeof(struct generator);
+}
+
static const rb_data_type_t generator_data_type = {
"generator",
{
generator_mark,
- RUBY_TYPED_DEFAULT_FREE,
- NULL,
+ generator_free,
+ generator_memsize,
generator_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct generator *
@@ -1474,7 +1494,7 @@ generator_init(VALUE obj, VALUE proc)
rb_raise(rb_eArgError, "unallocated generator");
}
- RB_OBJ_WRITE(obj, &ptr->proc, proc);
+ ptr->proc = proc;
return obj;
}
@@ -1522,7 +1542,7 @@ generator_init_copy(VALUE obj, VALUE orig)
rb_raise(rb_eArgError, "unallocated generator");
}
- RB_OBJ_WRITE(obj, &ptr1->proc, ptr0->proc);
+ ptr1->proc = ptr0->proc;
return obj;
}
@@ -1689,7 +1709,7 @@ lazy_generator_init(VALUE enumerator, VALUE procs)
lazy_init_block, rb_ary_new3(2, obj, procs));
gen_ptr = generator_ptr(generator);
- RB_OBJ_WRITE(generator, &gen_ptr->obj, obj);
+ gen_ptr->obj = obj;
return generator;
}
@@ -1874,10 +1894,10 @@ lazy_add_method(VALUE obj, int argc, VALUE *argv, VALUE args, VALUE memo,
VALUE entry_obj = TypedData_Make_Struct(rb_cObject, struct proc_entry,
&proc_entry_data_type, entry);
if (rb_block_given_p()) {
- RB_OBJ_WRITE(entry_obj, &entry->proc, rb_block_proc());
+ entry->proc = rb_block_proc();
}
entry->fn = fn;
- RB_OBJ_WRITE(entry_obj, &entry->memo, args);
+ entry->memo = args;
lazy_set_args(entry_obj, memo);
@@ -1886,9 +1906,9 @@ lazy_add_method(VALUE obj, int argc, VALUE *argv, VALUE args, VALUE memo,
rb_ary_push(new_procs, entry_obj);
new_obj = enumerator_init_copy(enumerator_allocate(rb_cLazy), obj);
- new_e = RTYPEDDATA_GET_DATA(new_obj);
- RB_OBJ_WRITE(new_obj, &new_e->obj, new_generator);
- RB_OBJ_WRITE(new_obj, &new_e->procs, new_procs);
+ new_e = DATA_PTR(new_obj);
+ new_e->obj = new_generator;
+ new_e->procs = new_procs;
if (argc > 0) {
new_e->meth = rb_to_id(*argv++);
@@ -1897,9 +1917,7 @@ lazy_add_method(VALUE obj, int argc, VALUE *argv, VALUE args, VALUE memo,
else {
new_e->meth = id_each;
}
-
- RB_OBJ_WRITE(new_obj, &new_e->args, rb_ary_new4(argc, argv));
-
+ new_e->args = rb_ary_new4(argc, argv);
return new_obj;
}
@@ -1985,7 +2003,7 @@ lazy_to_enum(int argc, VALUE *argv, VALUE self)
}
lazy = lazy_to_enum_i(self, meth, argc, argv, 0, rb_keyword_given_p());
if (rb_block_given_p()) {
- RB_OBJ_WRITE(lazy, &enumerator_ptr(lazy)->size, rb_block_proc());
+ enumerator_ptr(lazy)->size = rb_block_proc();
}
return lazy;
}
@@ -2371,6 +2389,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;
}
@@ -2945,7 +2964,7 @@ static const rb_data_type_t producer_data_type = {
producer_memsize,
producer_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct producer *
@@ -2985,8 +3004,8 @@ producer_init(VALUE obj, VALUE init, VALUE proc)
rb_raise(rb_eArgError, "unallocated producer");
}
- RB_OBJ_WRITE(obj, &ptr->init, init);
- RB_OBJ_WRITE(obj, &ptr->proc, proc);
+ ptr->init = init;
+ ptr->proc = proc;
return obj;
}
diff --git a/error.c b/error.c
index 9340bf5673..8aa081c198 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.
+ * +:deprecated+ :: deprecation warnings
+ * * assignment of non-nil value to <code>$,</code> and <code>$;</code>
+ * * keyword arguments
+ * * proc/lambda without block
+ * etc.
*
- * +:experimental+ ::
- * experimental features
- * * Pattern matching
- *
- * +:performance+ ::
- * performance hints
- * * Shape variation limit
+ * +:experimental+ :: experimental features
+ * * Pattern matching
*/
static VALUE
@@ -291,11 +279,11 @@ rb_warning_s_warn(int argc, VALUE *argv, VALUE mod)
*
* Changing the behavior of Warning.warn is useful to customize how warnings are
* handled by Ruby, for instance by filtering some warnings, and/or outputting
- * warnings somewhere other than <tt>$stderr</tt>.
+ * warnings somewhere other than $stderr.
*
* If you want to change the behavior of Warning.warn you should use
- * <tt>Warning.extend(MyNewModuleWithWarnMethod)</tt> and you can use +super+
- * to get the default behavior of printing the warning to <tt>$stderr</tt>.
+ * +Warning.extend(MyNewModuleWithWarnMethod)+ and you can use `super`
+ * to get the default behavior of printing the warning to $stderr.
*
* Example:
* module MyWarningFilter
@@ -312,7 +300,7 @@ rb_warning_s_warn(int argc, VALUE *argv, VALUE mod)
* You should never redefine Warning#warn (the instance method), as that will
* then no longer provide a way to use the default behavior.
*
- * The warning[https://rubygems.org/gems/warning] gem provides convenient ways to customize Warning.warn.
+ * The +warning+ gem provides convenient ways to customize Warning.warn.
*/
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) && rb_warning_category_enabled_p(category)) {
+ if (!NIL_P(ruby_verbose)) {
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) && rb_warning_category_enabled_p(category)) {
+ if (RTEST(ruby_verbose)) {
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)
@@ -1066,7 +814,6 @@ rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int sig, const voi
if (default_sighandler) default_sighandler(sig);
- ruby_default_signal(sig);
die();
}
@@ -1120,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;
@@ -1128,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();
}
@@ -1323,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;
@@ -1835,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);
@@ -2071,9 +1818,7 @@ name_err_init_attr(VALUE exc, VALUE recv, VALUE method)
cfp = rb_vm_get_ruby_level_next_cfp(ec, cfp);
rb_ivar_set(exc, id_name, method);
err_init_recv(exc, recv);
- if (cfp && VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_DUMMY) {
- rb_ivar_set(exc, id_iseq, rb_iseqw_new(cfp->iseq));
- }
+ if (cfp) rb_ivar_set(exc, id_iseq, rb_iseqw_new(cfp->iseq));
return exc;
}
@@ -2203,50 +1948,50 @@ rb_nomethod_err_new(VALUE mesg, VALUE recv, VALUE method, VALUE args, int priv)
return nometh_err_init_attr(exc, args, priv);
}
-typedef struct name_error_message_struct {
- VALUE mesg;
- VALUE recv;
- VALUE name;
-} name_error_message_t;
+/* :nodoc: */
+enum {
+ NAME_ERR_MESG__MESG,
+ NAME_ERR_MESG__RECV,
+ NAME_ERR_MESG__NAME,
+ NAME_ERR_MESG_COUNT
+};
static void
name_err_mesg_mark(void *p)
{
- name_error_message_t *ptr = (name_error_message_t *)p;
- rb_gc_mark_movable(ptr->mesg);
- rb_gc_mark_movable(ptr->recv);
- rb_gc_mark_movable(ptr->name);
+ VALUE *ptr = p;
+ rb_gc_mark_locations(ptr, ptr+NAME_ERR_MESG_COUNT);
}
-static void
-name_err_mesg_update(void *p)
+#define name_err_mesg_free RUBY_TYPED_DEFAULT_FREE
+
+static size_t
+name_err_mesg_memsize(const void *p)
{
- name_error_message_t *ptr = (name_error_message_t *)p;
- ptr->mesg = rb_gc_location(ptr->mesg);
- ptr->recv = rb_gc_location(ptr->recv);
- ptr->name = rb_gc_location(ptr->name);
+ return NAME_ERR_MESG_COUNT * sizeof(VALUE);
}
static const rb_data_type_t name_err_mesg_data_type = {
"name_err_mesg",
{
name_err_mesg_mark,
- RUBY_TYPED_DEFAULT_FREE,
- NULL, // No external memory to report,
- name_err_mesg_update,
+ name_err_mesg_free,
+ name_err_mesg_memsize,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
/* :nodoc: */
static VALUE
-rb_name_err_mesg_init(VALUE klass, VALUE mesg, VALUE recv, VALUE name)
+rb_name_err_mesg_init(VALUE klass, VALUE mesg, VALUE recv, VALUE method)
{
- name_error_message_t *message;
- VALUE result = TypedData_Make_Struct(klass, name_error_message_t, &name_err_mesg_data_type, message);
- RB_OBJ_WRITE(result, &message->mesg, mesg);
- RB_OBJ_WRITE(result, &message->recv, recv);
- RB_OBJ_WRITE(result, &message->name, name);
+ VALUE result = TypedData_Wrap_Struct(klass, &name_err_mesg_data_type, 0);
+ VALUE *ptr = ALLOC_N(VALUE, NAME_ERR_MESG_COUNT);
+
+ ptr[NAME_ERR_MESG__MESG] = mesg;
+ ptr[NAME_ERR_MESG__RECV] = recv;
+ ptr[NAME_ERR_MESG__NAME] = method;
+ RTYPEDDATA_DATA(result) = ptr;
return result;
}
@@ -2268,16 +2013,14 @@ name_err_mesg_alloc(VALUE klass)
static VALUE
name_err_mesg_init_copy(VALUE obj1, VALUE obj2)
{
+ VALUE *ptr1, *ptr2;
+
if (obj1 == obj2) return obj1;
rb_obj_init_copy(obj1, obj2);
- name_error_message_t *ptr1, *ptr2;
- TypedData_Get_Struct(obj1, name_error_message_t, &name_err_mesg_data_type, ptr1);
- TypedData_Get_Struct(obj2, name_error_message_t, &name_err_mesg_data_type, ptr2);
-
- RB_OBJ_WRITE(obj1, &ptr1->mesg, ptr2->mesg);
- RB_OBJ_WRITE(obj1, &ptr1->recv, ptr2->recv);
- RB_OBJ_WRITE(obj1, &ptr1->name, ptr2->name);
+ TypedData_Get_Struct(obj1, VALUE, &name_err_mesg_data_type, ptr1);
+ TypedData_Get_Struct(obj2, VALUE, &name_err_mesg_data_type, ptr2);
+ MEMCPY(ptr1, ptr2, VALUE, NAME_ERR_MESG_COUNT);
return obj1;
}
@@ -2285,18 +2028,19 @@ name_err_mesg_init_copy(VALUE obj1, VALUE obj2)
static VALUE
name_err_mesg_equal(VALUE obj1, VALUE obj2)
{
- if (obj1 == obj2) return Qtrue;
+ VALUE *ptr1, *ptr2;
+ int i;
+ if (obj1 == obj2) return Qtrue;
if (rb_obj_class(obj2) != rb_cNameErrorMesg)
return Qfalse;
- name_error_message_t *ptr1, *ptr2;
- TypedData_Get_Struct(obj1, name_error_message_t, &name_err_mesg_data_type, ptr1);
- TypedData_Get_Struct(obj2, name_error_message_t, &name_err_mesg_data_type, ptr2);
-
- if (!rb_equal(ptr1->mesg, ptr2->mesg)) return Qfalse;
- if (!rb_equal(ptr1->recv, ptr2->recv)) return Qfalse;
- if (!rb_equal(ptr1->name, ptr2->name)) return Qfalse;
+ TypedData_Get_Struct(obj1, VALUE, &name_err_mesg_data_type, ptr1);
+ TypedData_Get_Struct(obj2, VALUE, &name_err_mesg_data_type, ptr2);
+ for (i=0; i<NAME_ERR_MESG_COUNT; i++) {
+ if (!rb_equal(ptr1[i], ptr2[i]))
+ return Qfalse;
+ }
return Qtrue;
}
@@ -2315,91 +2059,51 @@ name_err_mesg_receiver_name(VALUE obj)
static VALUE
name_err_mesg_to_str(VALUE obj)
{
- name_error_message_t *ptr;
- TypedData_Get_Struct(obj, name_error_message_t, &name_err_mesg_data_type, ptr);
+ VALUE *ptr, mesg;
+ TypedData_Get_Struct(obj, VALUE, &name_err_mesg_data_type, ptr);
- VALUE mesg = ptr->mesg;
+ 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->recv;
+ 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;
}
- args[0] = rb_obj_as_string(ptr->name);
+ 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;
args[3] = c;
@@ -2432,17 +2136,17 @@ name_err_mesg_load(VALUE klass, VALUE str)
static VALUE
name_err_receiver(VALUE self)
{
- VALUE recv = rb_ivar_lookup(self, id_recv, Qundef);
+ VALUE *ptr, recv, mesg;
+
+ recv = rb_ivar_lookup(self, id_recv, Qundef);
if (!UNDEF_P(recv)) return recv;
- VALUE mesg = rb_attr_get(self, id_mesg);
+ mesg = rb_attr_get(self, id_mesg);
if (!rb_typeddata_is_kind_of(mesg, &name_err_mesg_data_type)) {
rb_raise(rb_eArgError, "no receiver is available");
}
-
- name_error_message_t *ptr;
- TypedData_Get_Struct(mesg, name_error_message_t, &name_err_mesg_data_type, ptr);
- return ptr->recv;
+ ptr = DATA_PTR(mesg);
+ return ptr[NAME_ERR_MESG__RECV];
}
/*
@@ -2694,14 +2398,6 @@ syntax_error_with_path(VALUE exc, VALUE path, VALUE *mesg, rb_encoding *enc)
static st_table *syserr_tbl;
-void
-rb_free_warning(void)
-{
- st_free_table(warning_categories.id2enum);
- st_free_table(warning_categories.enum2id);
- st_free_table(syserr_tbl);
-}
-
static VALUE
set_syserr(int n, const char *name)
{
@@ -3061,7 +2757,7 @@ syserr_eqq(VALUE self, VALUE exc)
*
* <em>raises the exception:</em>
*
- * NoMethodError: undefined method `to_ary' for an instance of String
+ * NoMethodError: undefined method `to_ary' for "hello":String
*/
/*
@@ -3257,9 +2953,9 @@ exception_dumper(VALUE exc)
}
static int
-ivar_copy_i(ID key, VALUE val, st_data_t exc)
+ivar_copy_i(st_data_t key, st_data_t val, st_data_t exc)
{
- rb_ivar_set((VALUE)exc, key, val);
+ rb_ivar_set((VALUE) exc, (ID) key, (VALUE) val);
return ST_CONTINUE;
}
@@ -3411,7 +3107,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();
@@ -3423,13 +3118,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
@@ -3512,7 +3205,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();
}
@@ -3575,14 +3268,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 a8fc48daf5..ff17ad343c 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:
@@ -645,10 +647,6 @@ rb_ec_setup_exception(const rb_execution_context_t *ec, VALUE mesg, VALUE cause)
cause = get_ec_errinfo(ec);
}
if (cause != mesg) {
- if (THROW_DATA_P(cause)) {
- cause = Qnil;
- }
-
rb_ivar_set(mesg, id_cause, cause);
}
}
@@ -1341,21 +1339,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_or_module
- *
- * Return the class or module refined by the receiver.
- *
- * module M
- * refine String do
- * end
- * end
+ * refined_class -> class
*
- * M.refinements[0].target # => String
+ * Return the class refined by the receiver.
*/
VALUE
rb_refinement_module_get_refined_class(VALUE module)
@@ -1366,21 +1357,6 @@ rb_refinement_module_get_refined_class(VALUE module)
return rb_attr_get(module, id_refined_class);
}
-/*
- * call-seq:
- * refined_class -> class
- *
- * Deprecated; prefer #target.
- *
- * 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)
@@ -1797,16 +1773,6 @@ 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
@@ -1819,7 +1785,13 @@ rb_top_main_class(const char *method)
static VALUE
top_include(int argc, VALUE *argv, VALUE self)
{
- return rb_mod_include(argc, argv, rb_top_main_class("include"));
+ 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);
}
/*
@@ -2093,8 +2065,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");
@@ -2123,21 +2094,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..948a205dd9 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;
}
@@ -461,12 +455,7 @@ exiting_split(VALUE errinfo, volatile int *exitcode, volatile int *sigstatus)
if (NIL_P(errinfo)) return 0;
- if (THROW_DATA_P(errinfo)) {
- int throw_state = ((const struct vm_throw_data *)errinfo)->throw_state;
- ex = throw_state & VM_THROW_STATE_MASK;
- result |= EXITING_WITH_STATUS;
- }
- else if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
+ if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
ex = sysexit_status(errinfo);
result |= EXITING_WITH_STATUS;
}
diff --git a/eval_intern.h b/eval_intern.h
index d008b17ca1..6cbaa51361 100644
--- a/eval_intern.h
+++ b/eval_intern.h
@@ -110,11 +110,9 @@ extern int select_large_fdset(int, fd_set *, fd_set *, fd_set *, struct timeval
_tag.tag = Qundef; \
_tag.prev = _ec->tag; \
_tag.lock_rec = rb_ec_vm_lock_rec(_ec); \
- rb_vm_tag_jmpbuf_init(&_tag.buf); \
#define EC_POP_TAG() \
_ec->tag = _tag.prev; \
- rb_vm_tag_jmpbuf_deinit(&_tag.buf); \
} while (0)
#define EC_TMPPOP_TAG() \
@@ -153,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;
}
@@ -161,9 +158,8 @@ 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(RB_VM_TAG_JMPBUF_GET(ec->tag->buf), 1);
+ ruby_longjmp(ec->tag->buf, 1);
}
/*
@@ -171,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(RB_VM_TAG_JMPBUF_GET(_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-/load/resolve_symbol_resolver/extconf.rb b/ext/-test-/load/resolve_symbol_resolver/extconf.rb
deleted file mode 100644
index 2299efcfd3..0000000000
--- a/ext/-test-/load/resolve_symbol_resolver/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/load/resolve_symbol_resolver')
diff --git a/ext/-test-/load/resolve_symbol_resolver/resolve_symbol_resolver.c b/ext/-test-/load/resolve_symbol_resolver/resolve_symbol_resolver.c
deleted file mode 100644
index a856319cfb..0000000000
--- a/ext/-test-/load/resolve_symbol_resolver/resolve_symbol_resolver.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <ruby.h>
-#include "ruby/internal/intern/load.h"
-
-typedef VALUE(*target_func)(VALUE);
-
-static target_func rst_any_method;
-
-VALUE
-rsr_any_method(VALUE klass)
-{
- return rst_any_method((VALUE)NULL);
-}
-
-VALUE
-rsr_try_resolve_fname(VALUE klass)
-{
- target_func rst_something_missing =
- (target_func) rb_ext_resolve_symbol("-test-/load/resolve_symbol_missing", "rst_any_method");
- if (rst_something_missing == NULL) {
- // This should be done in Init_*, so the error is LoadError
- rb_raise(rb_eLoadError, "symbol not found: missing fname");
- }
- return Qtrue;
-}
-
-VALUE
-rsr_try_resolve_sname(VALUE klass)
-{
- target_func rst_something_missing =
- (target_func)rb_ext_resolve_symbol("-test-/load/resolve_symbol_target", "rst_something_missing");
- if (rst_something_missing == NULL) {
- // This should be done in Init_*, so the error is LoadError
- rb_raise(rb_eLoadError, "symbol not found: missing sname");
- }
- return Qtrue;
-}
-
-void
-Init_resolve_symbol_resolver(void)
-{
- /*
- * Resolving symbols at the head of Init_ because it raises LoadError (in cases).
- * If the module and methods are defined before raising LoadError, retrying `require "this.so"` will
- * cause re-defining those methods (and will be warned).
- */
- rst_any_method = (target_func)rb_ext_resolve_symbol("-test-/load/resolve_symbol_target", "rst_any_method");
- if (rst_any_method == NULL) {
- rb_raise(rb_eLoadError, "resolve_symbol_target is not loaded");
- }
-
- VALUE mod = rb_define_module("ResolveSymbolResolver");
- rb_define_singleton_method(mod, "any_method", rsr_any_method, 0);
- rb_define_singleton_method(mod, "try_resolve_fname", rsr_try_resolve_fname, 0);
- rb_define_singleton_method(mod, "try_resolve_sname", rsr_try_resolve_sname, 0);
-}
diff --git a/ext/-test-/load/resolve_symbol_target/extconf.rb b/ext/-test-/load/resolve_symbol_target/extconf.rb
deleted file mode 100644
index b5a99ca7f1..0000000000
--- a/ext/-test-/load/resolve_symbol_target/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/load/resolve_symbol_target')
diff --git a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.c b/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.c
deleted file mode 100644
index b5bc9e8ee0..0000000000
--- a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <ruby.h>
-#include "resolve_symbol_target.h"
-
-VALUE
-rst_any_method(VALUE klass)
-{
- return rb_str_new_cstr("from target");
-}
-
-void
-Init_resolve_symbol_target(void)
-{
- VALUE mod = rb_define_module("ResolveSymbolTarget");
- rb_define_singleton_method(mod, "any_method", rst_any_method, 0);
-}
diff --git a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.def b/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.def
deleted file mode 100644
index c2ed3610fe..0000000000
--- a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.def
+++ /dev/null
@@ -1,4 +0,0 @@
-LIBRARY resolve_symbol_target
-EXPORTS
- Init_resolve_symbol_target
- rst_any_method
diff --git a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h b/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h
deleted file mode 100644
index 7d471bf360..0000000000
--- a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#include <ruby.h>
-#include "ruby/internal/dllexport.h"
-
-RUBY_EXTERN VALUE rst_any_method(VALUE);
diff --git a/ext/-test-/load/stringify_symbols/extconf.rb b/ext/-test-/load/stringify_symbols/extconf.rb
deleted file mode 100644
index ac39c15f09..0000000000
--- a/ext/-test-/load/stringify_symbols/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/load/stringify_symbols')
diff --git a/ext/-test-/load/stringify_symbols/stringify_symbols.c b/ext/-test-/load/stringify_symbols/stringify_symbols.c
deleted file mode 100644
index 11a5ee3bc5..0000000000
--- a/ext/-test-/load/stringify_symbols/stringify_symbols.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <ruby.h>
-#include "ruby/internal/intern/load.h"
-#include "ruby/util.h"
-
-#if SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
-# define UINTPTR2NUM ULL2NUM
-#elif SIZEOF_INTPTR_T == SIZEOF_LONG
-# define UINTPTR2NUM ULONG2NUM
-#else
-# define UINTPTR2NUM UINT2NUM
-#endif
-
-static VALUE
-stringify_symbol(VALUE klass, VALUE fname, VALUE sname)
-{
- void *ptr = rb_ext_resolve_symbol(StringValueCStr(fname), StringValueCStr(sname));
- if (ptr == NULL) {
- return Qnil;
- }
- uintptr_t uintptr = (uintptr_t)ptr;
- return UINTPTR2NUM(uintptr);
-}
-
-void
-Init_stringify_symbols(void)
-{
- VALUE mod = rb_define_module("StringifySymbols");
- rb_define_singleton_method(mod, "stringify_symbol", stringify_symbol, 2);
-}
diff --git a/ext/-test-/load/stringify_target/extconf.rb b/ext/-test-/load/stringify_target/extconf.rb
deleted file mode 100644
index 4aa201cb09..0000000000
--- a/ext/-test-/load/stringify_target/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/load/stringify_target')
diff --git a/ext/-test-/load/stringify_target/stringify_target.c b/ext/-test-/load/stringify_target/stringify_target.c
deleted file mode 100644
index ce09b8fd77..0000000000
--- a/ext/-test-/load/stringify_target/stringify_target.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <ruby.h>
-#include "stringify_target.h"
-
-VALUE
-stt_any_method(VALUE klass)
-{
- return rb_str_new_cstr("from target");
-}
-
-void
-Init_stringify_target(void)
-{
- VALUE mod = rb_define_module("StringifyTarget");
- rb_define_singleton_method(mod, "any_method", stt_any_method, 0);
-}
diff --git a/ext/-test-/load/stringify_target/stringify_target.def b/ext/-test-/load/stringify_target/stringify_target.def
deleted file mode 100644
index 89c2b762de..0000000000
--- a/ext/-test-/load/stringify_target/stringify_target.def
+++ /dev/null
@@ -1,4 +0,0 @@
-LIBRARY stringify_target
-EXPORTS
- Init_stringify_target
- stt_any_method
diff --git a/ext/-test-/load/stringify_target/stringify_target.h b/ext/-test-/load/stringify_target/stringify_target.h
deleted file mode 100644
index 5081f8cbd6..0000000000
--- a/ext/-test-/load/stringify_target/stringify_target.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#include <ruby.h>
-#include "ruby/internal/dllexport.h"
-
-RUBY_EXTERN VALUE stt_any_method(VALUE);
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-/postponed_job/postponed_job.c b/ext/-test-/postponed_job/postponed_job.c
index 9ac866ae77..fa57bef6f5 100644
--- a/ext/-test-/postponed_job/postponed_job.c
+++ b/ext/-test-/postponed_job/postponed_job.c
@@ -1,29 +1,6 @@
#include "ruby.h"
#include "ruby/debug.h"
-// We're testing deprecated things, don't print the compiler warnings
-#if 0
-
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4996)
-
-#elif defined(__INTEL_COMPILER)
-#pragma warning(disable : 1786)
-
-#elif defined(__clang__)
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
-#elif defined(__SUNPRO_CC)
-#pragma error_messages (off,symdeprecated)
-
-#else
-// :FIXME: improve here for your compiler.
-
-#endif
-
static int counter;
static void
@@ -81,22 +58,6 @@ pjob_call_direct(VALUE self, VALUE obj)
return self;
}
-static void pjob_noop_callback(void *data) { }
-
-static VALUE
-pjob_register_one_same(VALUE self)
-{
- rb_gc_start();
- int r1 = rb_postponed_job_register_one(0, pjob_noop_callback, NULL);
- int r2 = rb_postponed_job_register_one(0, pjob_noop_callback, NULL);
- int r3 = rb_postponed_job_register_one(0, pjob_noop_callback, NULL);
- VALUE ary = rb_ary_new();
- rb_ary_push(ary, INT2FIX(r1));
- rb_ary_push(ary, INT2FIX(r2));
- rb_ary_push(ary, INT2FIX(r3));
- return ary;
-}
-
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
@@ -125,93 +86,6 @@ pjob_register_in_c_thread(VALUE self, VALUE obj)
}
#endif
-static void
-pjob_preregistered_callback(void *data)
-{
- VALUE ary = (VALUE)data;
- Check_Type(ary, T_ARRAY);
- rb_ary_push(ary, INT2FIX(counter));
-}
-
-static VALUE
-pjob_preregister_and_call_with_sleep(VALUE self, VALUE obj)
-{
- counter = 0;
- rb_postponed_job_handle_t h = rb_postponed_job_preregister(0, pjob_preregistered_callback, (void *)obj);
- counter++;
- rb_postponed_job_trigger(h);
- rb_thread_sleep(0);
- counter++;
- rb_postponed_job_trigger(h);
- rb_thread_sleep(0);
- counter++;
- rb_postponed_job_trigger(h);
- rb_thread_sleep(0);
- return self;
-}
-
-static VALUE
-pjob_preregister_and_call_without_sleep(VALUE self, VALUE obj)
-{
- counter = 0;
- rb_postponed_job_handle_t h = rb_postponed_job_preregister(0, pjob_preregistered_callback, (void *)obj);
- counter = 3;
- rb_postponed_job_trigger(h);
- rb_postponed_job_trigger(h);
- rb_postponed_job_trigger(h);
- return self;
-}
-
-static VALUE
-pjob_preregister_multiple_times(VALUE self)
-{
- int r1 = rb_postponed_job_preregister(0, pjob_noop_callback, NULL);
- int r2 = rb_postponed_job_preregister(0, pjob_noop_callback, NULL);
- int r3 = rb_postponed_job_preregister(0, pjob_noop_callback, NULL);
- VALUE ary = rb_ary_new();
- rb_ary_push(ary, INT2FIX(r1));
- rb_ary_push(ary, INT2FIX(r2));
- rb_ary_push(ary, INT2FIX(r3));
- return ary;
-
-}
-
-struct pjob_append_data_args {
- VALUE ary;
- VALUE data;
-};
-
-static void
-pjob_append_data_callback(void *vctx) {
- struct pjob_append_data_args *ctx = (struct pjob_append_data_args *)vctx;
- Check_Type(ctx->ary, T_ARRAY);
- rb_ary_push(ctx->ary, ctx->data);
-}
-
-static VALUE
-pjob_preregister_calls_with_last_argument(VALUE self)
-{
- VALUE ary = rb_ary_new();
-
- struct pjob_append_data_args arg1 = { .ary = ary, .data = INT2FIX(1) };
- struct pjob_append_data_args arg2 = { .ary = ary, .data = INT2FIX(2) };
- struct pjob_append_data_args arg3 = { .ary = ary, .data = INT2FIX(3) };
- struct pjob_append_data_args arg4 = { .ary = ary, .data = INT2FIX(4) };
-
- rb_postponed_job_handle_t h;
- h = rb_postponed_job_preregister(0, pjob_append_data_callback, &arg1);
- rb_postponed_job_preregister(0, pjob_append_data_callback, &arg2);
- rb_postponed_job_trigger(h);
- rb_postponed_job_preregister(0, pjob_append_data_callback, &arg3);
- rb_thread_sleep(0); // should execute with arg3
-
- rb_postponed_job_preregister(0, pjob_append_data_callback, &arg4);
- rb_postponed_job_trigger(h);
- rb_thread_sleep(0); // should execute with arg4
-
- return ary;
-}
-
void
Init_postponed_job(VALUE self)
{
@@ -219,13 +93,8 @@ Init_postponed_job(VALUE self)
rb_define_module_function(mBug, "postponed_job_register", pjob_register, 1);
rb_define_module_function(mBug, "postponed_job_register_one", pjob_register_one, 1);
rb_define_module_function(mBug, "postponed_job_call_direct", pjob_call_direct, 1);
- rb_define_module_function(mBug, "postponed_job_register_one_same", pjob_register_one_same, 0);
#ifdef HAVE_PTHREAD_H
rb_define_module_function(mBug, "postponed_job_register_in_c_thread", pjob_register_in_c_thread, 1);
#endif
- rb_define_module_function(mBug, "postponed_job_preregister_and_call_with_sleep", pjob_preregister_and_call_with_sleep, 1);
- rb_define_module_function(mBug, "postponed_job_preregister_and_call_without_sleep", pjob_preregister_and_call_without_sleep, 1);
- rb_define_module_function(mBug, "postponed_job_preregister_multiple_times", pjob_preregister_multiple_times, 0);
- rb_define_module_function(mBug, "postponed_job_preregister_calls_with_last_argument", pjob_preregister_calls_with_last_argument, 0);
}
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 8dfa36e345..2374319fe3 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, NIL_P(encoding) ? NULL : RDATA(encoding)->data);
+ return rb_enc_interned_str("foo", 3, RDATA(encoding)->data);
}
VALUE
bug_s_rb_enc_str_new(VALUE self, VALUE encoding)
{
- return rb_enc_str_new("foo", 3, NIL_P(encoding) ? NULL : RDATA(encoding)->data);
+ return rb_enc_str_new("foo", 3, 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-/string/set_len.c b/ext/-test-/string/set_len.c
index 049da2cdb5..219cea404c 100644
--- a/ext/-test-/string/set_len.c
+++ b/ext/-test-/string/set_len.c
@@ -7,18 +7,8 @@ bug_str_set_len(VALUE str, VALUE len)
return str;
}
-static VALUE
-bug_str_append(VALUE str, VALUE addendum)
-{
- StringValue(addendum);
- rb_str_modify_expand(str, RSTRING_LEN(addendum));
- memcpy(RSTRING_END(str), RSTRING_PTR(addendum), RSTRING_LEN(addendum));
- return str;
-}
-
void
Init_string_set_len(VALUE klass)
{
rb_define_method(klass, "set_len", bug_str_set_len, 1);
- rb_define_method(klass, "append", bug_str_append, 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 d81bc0f2a7..d2a2c2740b 100644
--- a/ext/-test-/thread/instrumentation/instrumentation.c
+++ b/ext/-test-/thread/instrumentation/instrumentation.c
@@ -2,137 +2,90 @@
#include "ruby/atomic.h"
#include "ruby/thread.h"
-#ifndef RB_THREAD_LOCAL_SPECIFIER
-# define RB_THREAD_LOCAL_SPECIFIER
+static rb_atomic_t started_count = 0;
+static rb_atomic_t ready_count = 0;
+static rb_atomic_t resumed_count = 0;
+static rb_atomic_t suspended_count = 0;
+static rb_atomic_t exited_count = 0;
+
+#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 VALUE last_thread = Qnil;
-static VALUE timeline_value = Qnil;
-
-struct thread_event {
- VALUE thread;
- rb_event_flag_t event;
-};
-
-#define MAX_EVENTS 1024
-static struct thread_event event_timeline[MAX_EVENTS];
-static rb_atomic_t timeline_cursor;
-
-static void
-event_timeline_gc_mark(void *ptr) {
- rb_atomic_t cursor;
- for (cursor = 0; cursor < timeline_cursor; cursor++) {
- rb_gc_mark(event_timeline[cursor].thread);
- }
-}
-
-static const rb_data_type_t event_timeline_type = {
- "TestThreadInstrumentation/event_timeline",
- {event_timeline_gc_mark, NULL, NULL,},
- 0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY,
-};
+static RB_THREAD_LOCAL_SPECIFIER unsigned int local_ready_count = 0;
+static RB_THREAD_LOCAL_SPECIFIER unsigned int local_resumed_count = 0;
+static RB_THREAD_LOCAL_SPECIFIER unsigned int local_suspended_count = 0;
static void
-reset_timeline(void)
-{
- timeline_cursor = 0;
- memset(event_timeline, 0, sizeof(struct thread_event) * MAX_EVENTS);
-}
-
-static rb_event_flag_t
-find_last_event(VALUE thread)
-{
- rb_atomic_t cursor = timeline_cursor;
- if (cursor) {
- do {
- if (event_timeline[cursor].thread == thread){
- return event_timeline[cursor].event;
- }
- cursor--;
- } while (cursor > 0);
- }
- return 0;
-}
-
-static const char *
-event_name(rb_event_flag_t event)
+ex_callback(rb_event_flag_t event, const rb_internal_thread_event_data_t *event_data, void *user_data)
{
switch (event) {
case RUBY_INTERNAL_THREAD_EVENT_STARTED:
- return "started";
+ RUBY_ATOMIC_INC(started_count);
+ break;
case RUBY_INTERNAL_THREAD_EVENT_READY:
- return "ready";
+ RUBY_ATOMIC_INC(ready_count);
+ local_ready_count++;
+ break;
case RUBY_INTERNAL_THREAD_EVENT_RESUMED:
- return "resumed";
+ RUBY_ATOMIC_INC(resumed_count);
+ local_resumed_count++;
+ break;
case RUBY_INTERNAL_THREAD_EVENT_SUSPENDED:
- return "suspended";
+ RUBY_ATOMIC_INC(suspended_count);
+ local_suspended_count++;
+ break;
case RUBY_INTERNAL_THREAD_EVENT_EXITED:
- return "exited";
+ RUBY_ATOMIC_INC(exited_count);
+ break;
}
- return "no-event";
}
-static void
-unexpected(bool strict, const char *format, VALUE thread, rb_event_flag_t last_event)
+static rb_internal_thread_event_hook_t * single_hook = NULL;
+
+static VALUE
+thread_counters(VALUE thread)
{
- const char *last_event_name = event_name(last_event);
- if (strict) {
- rb_bug(format, thread, last_event_name);
- }
- else {
- fprintf(stderr, format, thread, last_event_name);
- fprintf(stderr, "\n");
- }
+ VALUE array = rb_ary_new2(5);
+ rb_ary_push(array, UINT2NUM(started_count));
+ rb_ary_push(array, UINT2NUM(ready_count));
+ rb_ary_push(array, UINT2NUM(resumed_count));
+ rb_ary_push(array, UINT2NUM(suspended_count));
+ rb_ary_push(array, UINT2NUM(exited_count));
+ return array;
}
-static void
-ex_callback(rb_event_flag_t event, const rb_internal_thread_event_data_t *event_data, void *user_data)
+static VALUE
+thread_local_counters(VALUE thread)
{
- rb_event_flag_t last_event = find_last_event(event_data->thread);
- bool strict = (bool)user_data;
-
- if (last_event != 0) {
- switch (event) {
- case RUBY_INTERNAL_THREAD_EVENT_STARTED:
- unexpected(strict, "[thread=%"PRIxVALUE"] `started` event can't be preceded by `%s`", event_data->thread, last_event);
- break;
- case RUBY_INTERNAL_THREAD_EVENT_READY:
- if (last_event != RUBY_INTERNAL_THREAD_EVENT_STARTED && last_event != RUBY_INTERNAL_THREAD_EVENT_SUSPENDED) {
- unexpected(strict, "[thread=%"PRIxVALUE"] `ready` must be preceded by `started` or `suspended`, got: `%s`", event_data->thread, last_event);
- }
- break;
- case RUBY_INTERNAL_THREAD_EVENT_RESUMED:
- if (last_event != RUBY_INTERNAL_THREAD_EVENT_READY) {
- unexpected(strict, "[thread=%"PRIxVALUE"] `resumed` must be preceded by `ready`, got: `%s`", event_data->thread, last_event);
- }
- break;
- case RUBY_INTERNAL_THREAD_EVENT_SUSPENDED:
- if (last_event != RUBY_INTERNAL_THREAD_EVENT_RESUMED) {
- unexpected(strict, "[thread=%"PRIxVALUE"] `suspended` must be preceded by `resumed`, got: `%s`", event_data->thread, last_event);
- }
- break;
- case RUBY_INTERNAL_THREAD_EVENT_EXITED:
- if (last_event != RUBY_INTERNAL_THREAD_EVENT_RESUMED && last_event != RUBY_INTERNAL_THREAD_EVENT_SUSPENDED) {
- unexpected(strict, "[thread=%"PRIxVALUE"] `exited` must be preceded by `resumed` or `suspended`, got: `%s`", event_data->thread, last_event);
- }
- break;
- }
- }
-
- rb_atomic_t cursor = RUBY_ATOMIC_FETCH_ADD(timeline_cursor, 1);
- if (cursor >= MAX_EVENTS) {
- rb_bug("TestThreadInstrumentation: ran out of event_timeline space");
- }
-
- event_timeline[cursor].thread = event_data->thread;
- event_timeline[cursor].event = event;
+ VALUE array = rb_ary_new2(3);
+ rb_ary_push(array, UINT2NUM(local_ready_count));
+ rb_ary_push(array, UINT2NUM(local_resumed_count));
+ rb_ary_push(array, UINT2NUM(local_suspended_count));
+ return array;
}
-static rb_internal_thread_event_hook_t * single_hook = NULL;
+static VALUE
+thread_reset_counters(VALUE thread)
+{
+ RUBY_ATOMIC_SET(started_count, 0);
+ RUBY_ATOMIC_SET(ready_count, 0);
+ RUBY_ATOMIC_SET(resumed_count, 0);
+ RUBY_ATOMIC_SET(suspended_count, 0);
+ RUBY_ATOMIC_SET(exited_count, 0);
+ local_ready_count = 0;
+ local_resumed_count = 0;
+ local_suspended_count = 0;
+ return Qtrue;
+}
static VALUE
-thread_register_callback(VALUE thread, VALUE strict)
+thread_register_callback(VALUE thread)
{
single_hook = rb_internal_thread_add_event_hook(
ex_callback,
@@ -141,33 +94,13 @@ thread_register_callback(VALUE thread, VALUE strict)
RUBY_INTERNAL_THREAD_EVENT_RESUMED |
RUBY_INTERNAL_THREAD_EVENT_SUSPENDED |
RUBY_INTERNAL_THREAD_EVENT_EXITED,
- (void *)RTEST(strict)
+ NULL
);
return Qnil;
}
static VALUE
-event_symbol(rb_event_flag_t event)
-{
- switch (event) {
- case RUBY_INTERNAL_THREAD_EVENT_STARTED:
- return rb_id2sym(rb_intern("started"));
- case RUBY_INTERNAL_THREAD_EVENT_READY:
- return rb_id2sym(rb_intern("ready"));
- case RUBY_INTERNAL_THREAD_EVENT_RESUMED:
- return rb_id2sym(rb_intern("resumed"));
- case RUBY_INTERNAL_THREAD_EVENT_SUSPENDED:
- return rb_id2sym(rb_intern("suspended"));
- case RUBY_INTERNAL_THREAD_EVENT_EXITED:
- return rb_id2sym(rb_intern("exited"));
- default:
- rb_bug("TestThreadInstrumentation: Unexpected event");
- break;
- }
-}
-
-static VALUE
thread_unregister_callback(VALUE thread)
{
if (single_hook) {
@@ -175,18 +108,7 @@ thread_unregister_callback(VALUE thread)
single_hook = NULL;
}
- VALUE events = rb_ary_new_capa(timeline_cursor);
- rb_atomic_t cursor;
- for (cursor = 0; cursor < timeline_cursor; cursor++) {
- VALUE pair = rb_ary_new_capa(2);
- rb_ary_push(pair, event_timeline[cursor].thread);
- rb_ary_push(pair, event_symbol(event_timeline[cursor].event));
- rb_ary_push(events, pair);
- }
-
- reset_timeline();
-
- return events;
+ return Qnil;
}
static VALUE
@@ -210,11 +132,10 @@ Init_instrumentation(void)
{
VALUE mBug = rb_define_module("Bug");
VALUE klass = rb_define_module_under(mBug, "ThreadInstrumentation");
- rb_global_variable(&timeline_value);
- timeline_value = TypedData_Wrap_Struct(0, &event_timeline_type, 0);
-
- rb_global_variable(&last_thread);
- rb_define_singleton_method(klass, "register_callback", thread_register_callback, 1);
+ rb_define_singleton_method(klass, "counters", thread_counters, 0);
+ rb_define_singleton_method(klass, "local_counters", thread_local_counters, 0);
+ rb_define_singleton_method(klass, "reset_counters", thread_reset_counters, 0);
+ rb_define_singleton_method(klass, "register_callback", thread_register_callback, 0);
rb_define_singleton_method(klass, "unregister_callback", thread_unregister_callback, 0);
rb_define_singleton_method(klass, "register_and_unregister_callbacks", thread_register_and_unregister_callback, 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-/tracepoint/gc_hook.c b/ext/-test-/tracepoint/gc_hook.c
index 54c06c54a5..a3f4e7f68a 100644
--- a/ext/-test-/tracepoint/gc_hook.c
+++ b/ext/-test-/tracepoint/gc_hook.c
@@ -33,9 +33,7 @@ gc_start_end_i(VALUE tpval, void *data)
}
if (invoking == 0) {
- /* will overwrite the existing handle with new data on the second and subsequent call */
- rb_postponed_job_handle_t h = rb_postponed_job_preregister(0, invoke_proc, data);
- rb_postponed_job_trigger(h);
+ rb_postponed_job_register(0, invoke_proc, data);
}
}
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 cb8874d31a..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;
}
@@ -4363,20 +4347,7 @@ BigDecimal_negative_zero(void)
* (2/3r).to_d(3) # => 0.667e0
* "0.5".to_d # => 0.5e0
*
- * == Methods for Working with \JSON
- *
- * - {::json_create}[rdoc-ref:BigDecimal.json_create]:
- * Returns a new \BigDecimal object constructed from the given object.
- * - {#as_json}[rdoc-ref:BigDecimal#as_json]:
- * Returns a 2-element hash representing +self+.
- * - {#to_json}[rdoc-ref:BigDecimal#to_json]:
- * Returns a \JSON string representing +self+.
- *
- * These methods are provided by the {JSON gem}[https://github.com/flori/json]. To make these methods available:
- *
- * require 'json/add/bigdecimal'
- *
- * * == License
+ * == License
*
* Copyright (C) 2002 by Shigeo Kobayashi <shigeo@tinyforest.gr.jp>.
*
@@ -4424,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
@@ -6479,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");
@@ -6719,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
}
/*
@@ -7179,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;
@@ -7217,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 495ad83aa3..c5b76de596 100644
--- a/ext/cgi/escape/escape.c
+++ b/ext/cgi/escape/escape.c
@@ -83,7 +83,7 @@ optimized_unescape_html(VALUE str)
unsigned long charlimit = (strcasecmp(rb_enc_name(enc), "UTF-8") == 0 ? UNICODE_MAX :
strcasecmp(rb_enc_name(enc), "ISO-8859-1") == 0 ? 256 :
128);
- long i, j, len, beg = 0;
+ long i, len, beg = 0;
size_t clen, plen;
int overflow;
const char *cstr;
@@ -100,7 +100,6 @@ optimized_unescape_html(VALUE str)
plen = i - beg;
if (++i >= len) break;
c = (unsigned char)cstr[i];
- j = i;
#define MATCH(s) (len - i >= (int)rb_strlen_lit(s) && \
memcmp(&cstr[i], s, rb_strlen_lit(s)) == 0 && \
(i += rb_strlen_lit(s) - 1, 1))
@@ -113,40 +112,28 @@ optimized_unescape_html(VALUE str)
else if (MATCH("mp;")) {
c = '&';
}
- else {
- i = j;
- continue;
- }
+ else continue;
break;
case 'q':
++i;
if (MATCH("uot;")) {
c = '"';
}
- else {
- i = j;
- continue;
- }
+ else continue;
break;
case 'g':
++i;
if (MATCH("t;")) {
c = '>';
}
- else {
- i = j;
- continue;
- }
+ else continue;
break;
case 'l':
++i;
if (MATCH("t;")) {
c = '<';
}
- else {
- i = j;
- continue;
- }
+ else continue;
break;
case '#':
if (len - ++i >= 2 && ISDIGIT(cstr[i])) {
@@ -155,15 +142,9 @@ optimized_unescape_html(VALUE str)
else if ((cstr[i] == 'x' || cstr[i] == 'X') && len - ++i >= 2 && ISXDIGIT(cstr[i])) {
cc = ruby_scan_digits(&cstr[i], len-i, 16, &clen, &overflow);
}
- else {
- i = j;
- continue;
- }
+ else continue;
i += clen;
- if (overflow || cc >= charlimit || cstr[i] != ';') {
- i = j;
- continue;
- }
+ if (overflow || cc >= charlimit || cstr[i] != ';') continue;
if (!dest) {
dest = rb_str_buf_new(len);
}
@@ -477,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 23127ca613..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"
+#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 da0b06aaa5..cab9a519c1 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,14 +136,6 @@ 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
@@ -167,6 +163,8 @@ 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
@@ -200,7 +198,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)) ||
@@ -263,8 +261,6 @@ 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]
@@ -553,13 +549,7 @@ extend Module.new {
end
def create_makefile(*args, &block)
- unless @gemname
- if $static and (target = args.first).include?("/")
- base = File.basename(target)
- $defs << "-DInit_#{base}=Init_#{target.tr('/', '_')}"
- end
- return super
- end
+ return super unless @gemname
super(*args) do |conf|
conf.find do |s|
s.sub!(%r(^(srcdir *= *)\$\(top_srcdir\)/\.bundle/gems/[^/]+(?=/))) {
@@ -774,13 +764,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|
@@ -843,17 +826,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 78eb11a209..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,40 +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
-
-/*
- * call-seq:
- * io.cursor -> [row, column]
- *
- * Returns the current cursor position as a two-element array of integers (row, column)
- *
- * io.cursor # => [3, 5]
- *
- * You must require 'io/console' to use this method.
- */
-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;
@@ -1189,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');
@@ -1234,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;
}
@@ -1264,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;
}
@@ -1299,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)
@@ -1389,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>
@@ -1438,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
@@ -1480,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;
}
@@ -1525,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)
{
@@ -1532,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);
@@ -1557,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;
}
@@ -1575,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)
@@ -1591,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);
}
@@ -1609,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
@@ -1622,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) \
@@ -1672,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..06ccdde70d 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
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 d4f52763b7..d26a757b01 100644
--- a/ext/io/console/io-console.gemspec
+++ b/ext/io/console/io-console.gemspec
@@ -1,5 +1,5 @@
# -*- ruby -*-
-_VERSION = "0.7.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/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/io-nonblock.gemspec b/ext/io/nonblock/io-nonblock.gemspec
index 6a16c8b03b..d6df21a84d 100644
--- a/ext/io/nonblock/io-nonblock.gemspec
+++ b/ext/io/nonblock/io-nonblock.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "io-nonblock"
- spec.version = "0.3.0"
+ spec.version = "0.2.0"
spec.authors = ["Nobu Nakada"]
spec.email = ["nobu@ruby-lang.org"]
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..eecdcce99f 100644
--- a/ext/io/wait/extconf.rb
+++ b/ext/io/wait/extconf.rb
@@ -6,7 +6,6 @@ if RUBY_VERSION < "2.6"
else
target = "io/wait"
have_func("rb_io_wait")
- have_func("rb_io_descriptor")
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/io-wait.gemspec b/ext/io/wait/io-wait.gemspec
index e850e10bf9..ebc1f6f5c7 100644
--- a/ext/io/wait/io-wait.gemspec
+++ b/ext/io/wait/io-wait.gemspec
@@ -1,4 +1,4 @@
-_VERSION = "0.3.1"
+_VERSION = "0.3.0"
Gem::Specification.new do |spec|
spec.name = "io-wait"
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/VERSION b/ext/json/VERSION
new file mode 100644
index 0000000000..ec1cf33c3f
--- /dev/null
+++ b/ext/json/VERSION
@@ -0,0 +1 @@
+2.6.3
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 6d78284bc4..98d0ea46c3 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -16,7 +16,7 @@ static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
i_pack, i_unpack, i_create_id, i_extend, i_key_p,
i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
- i_buffer_initial_length, i_dup, i_script_safe, i_escape_slash, i_strict;
+ i_buffer_initial_length, i_dup, i_escape_slash;
/*
* Copyright 2001-2004 Unicode, Inc.
@@ -124,7 +124,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
* and control characters are JSON escaped. */
-static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char script_safe)
+static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
{
const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
const UTF8 *sourceEnd = source + RSTRING_LEN(string);
@@ -175,7 +175,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char scrip
fbuffer_append(buffer, "\\\"", 2);
break;
case '/':
- if(script_safe) {
+ if(escape_slash) {
fbuffer_append(buffer, "\\/", 2);
break;
}
@@ -228,7 +228,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char scrip
* characters required by the JSON standard are JSON escaped. The remaining
* characters (should be UTF8) are just passed through and appended to the
* result. */
-static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe)
+static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
{
const char *ptr = RSTRING_PTR(string), *p;
unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
@@ -280,7 +280,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe
escape_len = 2;
break;
case '/':
- if(script_safe) {
+ if(escape_slash) {
escape = "\\/";
escape_len = 2;
break;
@@ -294,22 +294,6 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe
rb_raise(rb_path2class("JSON::GeneratorError"),
"partial character in source, but hit end");
}
-
- if (script_safe && c == 0xE2) {
- unsigned char c2 = (unsigned char) *(p+1);
- unsigned char c3 = (unsigned char) *(p+2);
- if (c2 == 0x80 && (c3 == 0xA8 || c3 == 0xA9)) {
- fbuffer_append(buffer, ptr + start, end - start);
- start = end = (end + clen);
- if (c3 == 0xA8) {
- fbuffer_append(buffer, "\\u2028", 6);
- } else {
- fbuffer_append(buffer, "\\u2029", 6);
- }
- continue;
- }
- }
-
if (!isLegalUTF8((UTF8 *) p, clen)) {
rb_raise(rb_path2class("JSON::GeneratorError"),
"source sequence is illegal/malformed utf-8");
@@ -494,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;
}
@@ -743,14 +726,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
state->allow_nan = RTEST(tmp);
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
state->ascii_only = RTEST(tmp);
- tmp = rb_hash_aref(opts, ID2SYM(i_script_safe));
- state->script_safe = RTEST(tmp);
- if (!state->script_safe) {
- tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
- state->script_safe = RTEST(tmp);
- }
- tmp = rb_hash_aref(opts, ID2SYM(i_strict));
- state->strict = RTEST(tmp);
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
+ state->escape_slash = RTEST(tmp);
return self;
}
@@ -785,8 +762,7 @@ static VALUE cState_to_h(VALUE self)
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
- rb_hash_aset(result, ID2SYM(i_script_safe), state->script_safe ? Qtrue : Qfalse);
- rb_hash_aset(result, ID2SYM(i_strict), state->strict ? Qtrue : Qfalse);
+ rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
return result;
@@ -867,7 +843,7 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
if (klass == rb_cString) {
key_to_s = key;
} else if (klass == rb_cSymbol) {
- key_to_s = rb_sym2str(key);
+ key_to_s = rb_id2str(SYM2ID(key));
} else {
key_to_s = rb_funcall(key, i_to_s, 0);
}
@@ -892,6 +868,7 @@ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
struct hash_foreach_arg arg;
if (max_nesting != 0 && depth > max_nesting) {
+ fbuffer_free(buffer);
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
}
fbuffer_append_char(buffer, '{');
@@ -926,6 +903,7 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
long depth = ++state->depth;
int i, j;
if (max_nesting != 0 && depth > max_nesting) {
+ fbuffer_free(buffer);
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
}
fbuffer_append_char(buffer, '[');
@@ -969,9 +947,9 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
}
#endif
if (state->ascii_only) {
- convert_UTF8_to_JSON_ASCII(buffer, obj, state->script_safe);
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
} else {
- convert_UTF8_to_JSON(buffer, obj, state->script_safe);
+ convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
}
fbuffer_append_char(buffer, '"');
}
@@ -1018,8 +996,10 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
VALUE tmp = rb_funcall(obj, i_to_s, 0);
if (!allow_nan) {
if (isinf(value)) {
+ fbuffer_free(buffer);
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp));
} else if (isnan(value)) {
+ fbuffer_free(buffer);
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp));
}
}
@@ -1048,8 +1028,6 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
generate_json_bignum(buffer, Vstate, state, obj);
} else if (klass == rb_cFloat) {
generate_json_float(buffer, Vstate, state, obj);
- } else if (state->strict) {
- rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(CLASS_OF(obj)));
} else if (rb_respond_to(obj, i_to_json)) {
tmp = rb_funcall(obj, i_to_json, 1, Vstate);
Check_Type(tmp, T_STRING);
@@ -1092,45 +1070,11 @@ static FBuffer *cState_prepare_buffer(VALUE self)
return buffer;
}
-struct generate_json_data {
- FBuffer *buffer;
- VALUE vstate;
- JSON_Generator_State *state;
- VALUE obj;
-};
-
-static VALUE generate_json_try(VALUE d)
-{
- struct generate_json_data *data = (struct generate_json_data *)d;
-
- generate_json(data->buffer, data->vstate, data->state, data->obj);
-
- return Qnil;
-}
-
-static VALUE generate_json_rescue(VALUE d, VALUE exc)
-{
- struct generate_json_data *data = (struct generate_json_data *)d;
- fbuffer_free(data->buffer);
-
- rb_exc_raise(exc);
-
- return Qundef;
-}
-
static VALUE cState_partial_generate(VALUE self, VALUE obj)
{
FBuffer *buffer = cState_prepare_buffer(self);
GET_STATE(self);
-
- struct generate_json_data data = {
- .buffer = buffer,
- .vstate = self,
- .state = state,
- .obj = obj
- };
- rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
-
+ generate_json(buffer, self, state, obj);
return fbuffer_to_s(buffer);
}
@@ -1446,58 +1390,27 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
}
/*
- * call-seq: script_safe
+ * call-seq: escape_slash
*
* If this boolean is true, the forward slashes will be escaped in
* the json output.
*/
-static VALUE cState_script_safe(VALUE self)
+static VALUE cState_escape_slash(VALUE self)
{
GET_STATE(self);
- return state->script_safe ? Qtrue : Qfalse;
+ return state->escape_slash ? Qtrue : Qfalse;
}
/*
- * call-seq: script_safe=(enable)
+ * call-seq: escape_slash=(depth)
*
* This sets whether or not the forward slashes will be escaped in
* the json output.
*/
-static VALUE cState_script_safe_set(VALUE self, VALUE enable)
-{
- GET_STATE(self);
- state->script_safe = RTEST(enable);
- return Qnil;
-}
-
-/*
- * call-seq: strict
- *
- * If this boolean is false, types unsupported by the JSON format will
- * be serialized as strings.
- * If this boolean is true, types unsupported by the JSON format will
- * raise a JSON::GeneratorError.
- */
-static VALUE cState_strict(VALUE self)
-{
- GET_STATE(self);
- return state->strict ? Qtrue : Qfalse;
-}
-
-/*
- * call-seq: strict=(enable)
- *
- * This sets whether or not to serialize types unsupported by the
- * JSON format as strings.
- * If this boolean is false, types unsupported by the JSON format will
- * be serialized as strings.
- * If this boolean is true, types unsupported by the JSON format will
- * raise a JSON::GeneratorError.
- */
-static VALUE cState_strict_set(VALUE self, VALUE enable)
+static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
{
GET_STATE(self);
- state->strict = RTEST(enable);
+ state->escape_slash = RTEST(enable);
return Qnil;
}
@@ -1617,15 +1530,9 @@ void Init_generator(void)
rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
- rb_define_method(cState, "script_safe", cState_script_safe, 0);
- rb_define_method(cState, "script_safe?", cState_script_safe, 0);
- rb_define_method(cState, "script_safe=", cState_script_safe_set, 1);
- rb_define_alias(cState, "escape_slash", "script_safe");
- rb_define_alias(cState, "escape_slash?", "script_safe?");
- rb_define_alias(cState, "escape_slash=", "script_safe=");
- rb_define_method(cState, "strict", cState_strict, 0);
- rb_define_method(cState, "strict?", cState_strict, 0);
- rb_define_method(cState, "strict=", cState_strict_set, 1);
+ rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
+ rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
+ rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
@@ -1682,9 +1589,7 @@ void Init_generator(void)
i_object_nl = rb_intern("object_nl");
i_array_nl = rb_intern("array_nl");
i_max_nesting = rb_intern("max_nesting");
- i_script_safe = rb_intern("script_safe");
i_escape_slash = rb_intern("escape_slash");
- i_strict = rb_intern("strict");
i_allow_nan = rb_intern("allow_nan");
i_ascii_only = rb_intern("ascii_only");
i_depth = rb_intern("depth");
diff --git a/ext/json/generator/generator.h b/ext/json/generator/generator.h
index 1a736b84dd..3ebd622554 100644
--- a/ext/json/generator/generator.h
+++ b/ext/json/generator/generator.h
@@ -49,8 +49,8 @@ static const UTF32 halfMask = 0x3FFUL;
static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length);
static void unicode_escape(char *buf, UTF16 character);
static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 character);
-static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char script_safe);
-static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe);
+static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash);
+static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash);
static char *fstrndup(const char *ptr, unsigned long len);
/* ruby api and some helpers */
@@ -72,8 +72,7 @@ typedef struct JSON_Generator_StateStruct {
long max_nesting;
char allow_nan;
char ascii_only;
- char script_safe;
- char strict;
+ char escape_slash;
long depth;
long buffer_initial_length;
} JSON_Generator_State;
@@ -152,10 +151,8 @@ static VALUE cState_allow_nan_p(VALUE self);
static VALUE cState_ascii_only_p(VALUE self);
static VALUE cState_depth(VALUE self);
static VALUE cState_depth_set(VALUE self, VALUE depth);
-static VALUE cState_script_safe(VALUE self);
-static VALUE cState_script_safe_set(VALUE self, VALUE depth);
-static VALUE cState_strict(VALUE self);
-static VALUE cState_strict_set(VALUE self, VALUE strict);
+static VALUE cState_escape_slash(VALUE self);
+static VALUE cState_escape_slash_set(VALUE self, VALUE depth);
static FBuffer *cState_prepare_buffer(VALUE self);
#ifndef ZALLOC
#define ZALLOC(type) ((type *)ruby_zalloc(sizeof(type)))
diff --git a/ext/json/json.gemspec b/ext/json/json.gemspec
index 64d0c81391..948e92c501 100644
--- a/ext/json/json.gemspec
+++ b/ext/json/json.gemspec
@@ -1,10 +1,8 @@
-version = File.foreach(File.join(__dir__, "lib/json/version.rb")) do |line|
- /^\s*VERSION\s*=\s*'(.*)'/ =~ line and break $1
-end rescue nil
+# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = "json"
- s.version = version
+ s.version = File.read(File.expand_path('../VERSION', __FILE__)).chomp
s.summary = "JSON Implementation for Ruby"
s.description = "This is a JSON implementation as a Ruby extension in C."
@@ -19,6 +17,7 @@ Gem::Specification.new do |s|
"CHANGES.md",
"LICENSE",
"README.md",
+ "VERSION",
"ext/json/ext/fbuffer/fbuffer.h",
"ext/json/ext/generator/depend",
"ext/json/ext/generator/extconf.rb",
@@ -54,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.rb b/ext/json/lib/json.rb
index 807488ffef..1e64bfcb1a 100644
--- a/ext/json/lib/json.rb
+++ b/ext/json/lib/json.rb
@@ -285,15 +285,6 @@ require 'json/common'
# # Raises JSON::NestingError (nesting of 2 is too deep):
# JSON.generate(obj, max_nesting: 2)
#
-# ====== Escaping Options
-#
-# Options +script_safe+ (boolean) specifies wether <tt>'\u2028'</tt>, <tt>'\u2029'</tt>
-# and <tt>'/'</tt> should be escaped as to make the JSON object safe to interpolate in script
-# tags.
-#
-# Options +ascii_only+ (boolean) specifies wether all characters outside the ASCII range
-# should be escaped.
-#
# ====== Output Options
#
# The default formatting options generate the most compact
diff --git a/ext/json/lib/json/add/bigdecimal.rb b/ext/json/lib/json/add/bigdecimal.rb
index b1d0cfa043..c8b4f567cb 100644
--- a/ext/json/lib/json/add/bigdecimal.rb
+++ b/ext/json/lib/json/add/bigdecimal.rb
@@ -2,36 +2,19 @@
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
-
- # See #as_json.
+ # Import a JSON Marshalled object.
+ #
+ # method used for JSON marshalling support.
def self.json_create(object)
BigDecimal._load object['b']
end
- # Methods <tt>BigDecimal#as_json</tt> and +BigDecimal.json_create+ may be used
- # to serialize and deserialize a \BigDecimal object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>BigDecimal#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/bigdecimal'
- # x = BigDecimal(2).as_json # => {"json_class"=>"BigDecimal", "b"=>"27:0.2e1"}
- # y = BigDecimal(2.0, 4).as_json # => {"json_class"=>"BigDecimal", "b"=>"36:0.2e1"}
- # z = BigDecimal(Complex(2, 0)).as_json # => {"json_class"=>"BigDecimal", "b"=>"27:0.2e1"}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \BigDecimal object:
- #
- # BigDecimal.json_create(x) # => 0.2e1
- # BigDecimal.json_create(y) # => 0.2e1
- # BigDecimal.json_create(z) # => 0.2e1
+ # Marshal the object to JSON.
#
+ # method used for JSON marshalling support.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -39,20 +22,8 @@ class BigDecimal
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/bigdecimal'
- # puts BigDecimal(2).to_json
- # puts BigDecimal(2.0, 4).to_json
- # puts BigDecimal(Complex(2, 0)).to_json
- #
- # Output:
- #
- # {"json_class":"BigDecimal","b":"27:0.2e1"}
- # {"json_class":"BigDecimal","b":"36:0.2e1"}
- # {"json_class":"BigDecimal","b":"27:0.2e1"}
- #
+ # return the JSON value
def to_json(*args)
as_json.to_json(*args)
end
-end if defined?(::BigDecimal)
+end
diff --git a/ext/json/lib/json/add/complex.rb b/ext/json/lib/json/add/complex.rb
index ef48c554c6..e63e29fd22 100644
--- a/ext/json/lib/json/add/complex.rb
+++ b/ext/json/lib/json/add/complex.rb
@@ -5,27 +5,14 @@ end
class Complex
- # See #as_json.
+ # Deserializes JSON string by converting Real value <tt>r</tt>, imaginary
+ # value <tt>i</tt>, to a Complex object.
def self.json_create(object)
Complex(object['r'], object['i'])
end
- # Methods <tt>Complex#as_json</tt> and +Complex.json_create+ may be used
- # to serialize and deserialize a \Complex object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Complex#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/complex'
- # x = Complex(2).as_json # => {"json_class"=>"Complex", "r"=>2, "i"=>0}
- # y = Complex(2.0, 4).as_json # => {"json_class"=>"Complex", "r"=>2.0, "i"=>4}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Complex object:
- #
- # Complex.json_create(x) # => (2+0i)
- # Complex.json_create(y) # => (2.0+4i)
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -34,17 +21,7 @@ class Complex
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/complex'
- # puts Complex(2).to_json
- # puts Complex(2.0, 4).to_json
- #
- # Output:
- #
- # {"json_class":"Complex","r":2,"i":0}
- # {"json_class":"Complex","r":2.0,"i":4}
- #
+ # Stores class name (Complex) along with real value <tt>r</tt> and imaginary value <tt>i</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/date.rb b/ext/json/lib/json/add/date.rb
index 19688f751b..25523561a5 100644
--- a/ext/json/lib/json/add/date.rb
+++ b/ext/json/lib/json/add/date.rb
@@ -6,29 +6,16 @@ require 'date'
class Date
- # See #as_json.
+ # Deserializes JSON string by converting Julian year <tt>y</tt>, month
+ # <tt>m</tt>, day <tt>d</tt> and Day of Calendar Reform <tt>sg</tt> to Date.
def self.json_create(object)
civil(*object.values_at('y', 'm', 'd', 'sg'))
end
alias start sg unless method_defined?(:start)
- # Methods <tt>Date#as_json</tt> and +Date.json_create+ may be used
- # to serialize and deserialize a \Date object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Date#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/date'
- # x = Date.today.as_json
- # # => {"json_class"=>"Date", "y"=>2023, "m"=>11, "d"=>21, "sg"=>2299161.0}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Date object:
- #
- # Date.json_create(x)
- # # => #<Date: 2023-11-21 ((2460270j,0s,0n),+0s,2299161j)>
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -39,15 +26,8 @@ class Date
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/date'
- # puts Date.today.to_json
- #
- # Output:
- #
- # {"json_class":"Date","y":2023,"m":11,"d":21,"sg":2299161.0}
- #
+ # Stores class name (Date) with Julian year <tt>y</tt>, month <tt>m</tt>, day
+ # <tt>d</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/date_time.rb b/ext/json/lib/json/add/date_time.rb
index d7d42591cf..38b0e86ab8 100644
--- a/ext/json/lib/json/add/date_time.rb
+++ b/ext/json/lib/json/add/date_time.rb
@@ -6,7 +6,9 @@ require 'date'
class DateTime
- # See #as_json.
+ # Deserializes JSON string by converting year <tt>y</tt>, month <tt>m</tt>,
+ # day <tt>d</tt>, hour <tt>H</tt>, minute <tt>M</tt>, second <tt>S</tt>,
+ # offset <tt>of</tt> and Day of Calendar Reform <tt>sg</tt> to DateTime.
def self.json_create(object)
args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
of_a, of_b = object['of'].split('/')
@@ -21,21 +23,8 @@ class DateTime
alias start sg unless method_defined?(:start)
- # Methods <tt>DateTime#as_json</tt> and +DateTime.json_create+ may be used
- # to serialize and deserialize a \DateTime object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>DateTime#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/datetime'
- # x = DateTime.now.as_json
- # # => {"json_class"=>"DateTime", "y"=>2023, "m"=>11, "d"=>21, "sg"=>2299161.0}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \DateTime object:
- #
- # DateTime.json_create(x) # BUG? Raises Date::Error "invalid date"
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -50,15 +39,9 @@ class DateTime
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/datetime'
- # puts DateTime.now.to_json
- #
- # Output:
- #
- # {"json_class":"DateTime","y":2023,"m":11,"d":21,"sg":2299161.0}
- #
+ # Stores class name (DateTime) with Julian year <tt>y</tt>, month <tt>m</tt>,
+ # day <tt>d</tt>, hour <tt>H</tt>, minute <tt>M</tt>, second <tt>S</tt>,
+ # offset <tt>of</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/exception.rb b/ext/json/lib/json/add/exception.rb
index 71d8deb0ea..a107e5b3c4 100644
--- a/ext/json/lib/json/add/exception.rb
+++ b/ext/json/lib/json/add/exception.rb
@@ -5,27 +5,16 @@ end
class Exception
- # See #as_json.
+ # Deserializes JSON string by constructing new Exception object with message
+ # <tt>m</tt> and backtrace <tt>b</tt> serialized with <tt>to_json</tt>
def self.json_create(object)
result = new(object['m'])
result.set_backtrace object['b']
result
end
- # Methods <tt>Exception#as_json</tt> and +Exception.json_create+ may be used
- # to serialize and deserialize a \Exception object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Exception#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/exception'
- # x = Exception.new('Foo').as_json # => {"json_class"=>"Exception", "m"=>"Foo", "b"=>nil}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Exception object:
- #
- # Exception.json_create(x) # => #<Exception: Foo>
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -34,15 +23,8 @@ class Exception
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/exception'
- # puts Exception.new('Foo').to_json
- #
- # Output:
- #
- # {"json_class":"Exception","m":"Foo","b":null}
- #
+ # Stores class name (Exception) with message <tt>m</tt> and backtrace array
+ # <tt>b</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/ostruct.rb b/ext/json/lib/json/add/ostruct.rb
index 1e6f408248..686cf0025d 100644
--- a/ext/json/lib/json/add/ostruct.rb
+++ b/ext/json/lib/json/add/ostruct.rb
@@ -2,34 +2,18 @@
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
require 'json'
end
-begin
- require 'ostruct'
-rescue LoadError
-end
+require 'ostruct'
class OpenStruct
- # See #as_json.
+ # Deserializes JSON string by constructing new Struct object with values
+ # <tt>t</tt> serialized by <tt>to_json</tt>.
def self.json_create(object)
new(object['t'] || object[:t])
end
- # Methods <tt>OpenStruct#as_json</tt> and +OpenStruct.json_create+ may be used
- # to serialize and deserialize a \OpenStruct object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>OpenStruct#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/ostruct'
- # x = OpenStruct.new('name' => 'Rowdy', :age => nil).as_json
- # # => {"json_class"=>"OpenStruct", "t"=>{:name=>'Rowdy', :age=>nil}}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \OpenStruct object:
- #
- # OpenStruct.json_create(x)
- # # => #<OpenStruct name='Rowdy', age=nil>
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
klass = self.class.name
klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
@@ -39,16 +23,9 @@ class OpenStruct
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/ostruct'
- # puts OpenStruct.new('name' => 'Rowdy', :age => nil).to_json
- #
- # Output:
- #
- # {"json_class":"OpenStruct","t":{'name':'Rowdy',"age":null}}
- #
+ # Stores class name (OpenStruct) with this struct's values <tt>t</tt> as a
+ # JSON string.
def to_json(*args)
as_json.to_json(*args)
end
-end if defined?(::OpenStruct)
+end
diff --git a/ext/json/lib/json/add/range.rb b/ext/json/lib/json/add/range.rb
index 53f54ac372..93529fb1c4 100644
--- a/ext/json/lib/json/add/range.rb
+++ b/ext/json/lib/json/add/range.rb
@@ -5,29 +5,14 @@ end
class Range
- # See #as_json.
+ # 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
- # Methods <tt>Range#as_json</tt> and +Range.json_create+ may be used
- # to serialize and deserialize a \Range object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Range#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/range'
- # x = (1..4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, false]}
- # y = (1...4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, true]}
- # z = ('a'..'d').as_json # => {"json_class"=>"Range", "a"=>["a", "d", false]}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Range object:
- #
- # Range.json_create(x) # => 1..4
- # Range.json_create(y) # => 1...4
- # Range.json_create(z) # => "a".."d"
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -35,19 +20,9 @@ class Range
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/range'
- # puts (1..4).to_json
- # puts (1...4).to_json
- # puts ('a'..'d').to_json
- #
- # Output:
- #
- # {"json_class":"Range","a":[1,4,false]}
- # {"json_class":"Range","a":[1,4,true]}
- # {"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/add/rational.rb b/ext/json/lib/json/add/rational.rb
index 8c39a7db55..f776226046 100644
--- a/ext/json/lib/json/add/rational.rb
+++ b/ext/json/lib/json/add/rational.rb
@@ -4,28 +4,14 @@ unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
end
class Rational
-
- # See #as_json.
+ # Deserializes JSON string by converting numerator value <tt>n</tt>,
+ # denominator value <tt>d</tt>, to a Rational object.
def self.json_create(object)
Rational(object['n'], object['d'])
end
- # Methods <tt>Rational#as_json</tt> and +Rational.json_create+ may be used
- # to serialize and deserialize a \Rational object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Rational#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/rational'
- # x = Rational(2, 3).as_json
- # # => {"json_class"=>"Rational", "n"=>2, "d"=>3}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Rational object:
- #
- # Rational.json_create(x)
- # # => (2/3)
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -34,15 +20,7 @@ class Rational
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/rational'
- # puts Rational(2, 3).to_json
- #
- # Output:
- #
- # {"json_class":"Rational","n":2,"d":3}
- #
+ # Stores class name (Rational) along with numerator value <tt>n</tt> and denominator value <tt>d</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/regexp.rb b/ext/json/lib/json/add/regexp.rb
index b63f49608f..39d69fede7 100644
--- a/ext/json/lib/json/add/regexp.rb
+++ b/ext/json/lib/json/add/regexp.rb
@@ -5,26 +5,15 @@ end
class Regexp
- # See #as_json.
+ # Deserializes JSON string by constructing new Regexp object with source
+ # <tt>s</tt> (Regexp or String) and options <tt>o</tt> serialized by
+ # <tt>to_json</tt>
def self.json_create(object)
new(object['s'], object['o'])
end
- # Methods <tt>Regexp#as_json</tt> and +Regexp.json_create+ may be used
- # to serialize and deserialize a \Regexp object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Regexp#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/regexp'
- # x = /foo/.as_json
- # # => {"json_class"=>"Regexp", "o"=>0, "s"=>"foo"}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Regexp object:
- #
- # Regexp.json_create(x) # => /foo/
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -33,15 +22,8 @@ class Regexp
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/regexp'
- # puts /foo/.to_json
- #
- # Output:
- #
- # {"json_class":"Regexp","o":0,"s":"foo"}
- #
+ # Stores class name (Regexp) with options <tt>o</tt> and source <tt>s</tt>
+ # (Regexp or String) as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/set.rb b/ext/json/lib/json/add/set.rb
index 1918353187..71e2a0ac8b 100644
--- a/ext/json/lib/json/add/set.rb
+++ b/ext/json/lib/json/add/set.rb
@@ -4,27 +4,16 @@ end
defined?(::Set) or require 'set'
class Set
-
- # See #as_json.
+ # Import a JSON Marshalled object.
+ #
+ # method used for JSON marshalling support.
def self.json_create(object)
new object['a']
end
- # Methods <tt>Set#as_json</tt> and +Set.json_create+ may be used
- # to serialize and deserialize a \Set object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Set#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/set'
- # x = Set.new(%w/foo bar baz/).as_json
- # # => {"json_class"=>"Set", "a"=>["foo", "bar", "baz"]}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Set object:
- #
- # Set.json_create(x) # => #<Set: {"foo", "bar", "baz"}>
+ # Marshal the object to JSON.
#
+ # method used for JSON marshalling support.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -32,15 +21,7 @@ class Set
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/set'
- # puts Set.new(%w/foo bar baz/).to_json
- #
- # Output:
- #
- # {"json_class":"Set","a":["foo","bar","baz"]}
- #
+ # return the JSON value
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/struct.rb b/ext/json/lib/json/add/struct.rb
index 86847762ac..e8395ed42f 100644
--- a/ext/json/lib/json/add/struct.rb
+++ b/ext/json/lib/json/add/struct.rb
@@ -5,28 +5,14 @@ end
class Struct
- # See #as_json.
+ # Deserializes JSON string by constructing new Struct object with values
+ # <tt>v</tt> serialized by <tt>to_json</tt>.
def self.json_create(object)
new(*object['v'])
end
- # Methods <tt>Struct#as_json</tt> and +Struct.json_create+ may be used
- # to serialize and deserialize a \Struct object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Struct#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/struct'
- # Customer = Struct.new('Customer', :name, :address, :zip)
- # x = Struct::Customer.new.as_json
- # # => {"json_class"=>"Struct::Customer", "v"=>[nil, nil, nil]}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Struct object:
- #
- # Struct::Customer.json_create(x)
- # # => #<struct Struct::Customer name=nil, address=nil, zip=nil>
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
klass = self.class.name
klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
@@ -36,16 +22,8 @@ class Struct
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/struct'
- # Customer = Struct.new('Customer', :name, :address, :zip)
- # puts Struct::Customer.new.to_json
- #
- # Output:
- #
- # {"json_class":"Struct","t":{'name':'Rowdy',"age":null}}
- #
+ # Stores class name (Struct) with Struct values <tt>v</tt> as a JSON string.
+ # Only named structs are supported.
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/symbol.rb b/ext/json/lib/json/add/symbol.rb
index b5f3623158..74b13a423f 100644
--- a/ext/json/lib/json/add/symbol.rb
+++ b/ext/json/lib/json/add/symbol.rb
@@ -1,26 +1,11 @@
-
#frozen_string_literal: false
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
require 'json'
end
class Symbol
-
- # Methods <tt>Symbol#as_json</tt> and +Symbol.json_create+ may be used
- # to serialize and deserialize a \Symbol object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Symbol#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/symbol'
- # x = :foo.as_json
- # # => {"json_class"=>"Symbol", "s"=>"foo"}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Symbol object:
- #
- # Symbol.json_create(x) # => :foo
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -28,20 +13,12 @@ class Symbol
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/symbol'
- # puts :foo.to_json
- #
- # Output:
- #
- # # {"json_class":"Symbol","s":"foo"}
- #
+ # Stores class name (Symbol) with String representation of Symbol as a JSON string.
def to_json(*a)
as_json.to_json(*a)
end
- # See #as_json.
+ # Deserializes JSON string by converting the <tt>string</tt> value stored in the object to a Symbol
def self.json_create(o)
o['s'].to_sym
end
diff --git a/ext/json/lib/json/add/time.rb b/ext/json/lib/json/add/time.rb
index 599ed9e24b..b73acc4086 100644
--- a/ext/json/lib/json/add/time.rb
+++ b/ext/json/lib/json/add/time.rb
@@ -5,7 +5,7 @@ end
class Time
- # See #as_json.
+ # Deserializes JSON string by converting time since epoch to Time
def self.json_create(object)
if usec = object.delete('u') # used to be tv_usec -> tv_nsec
object['n'] = usec * 1000
@@ -17,22 +17,8 @@ class Time
end
end
- # Methods <tt>Time#as_json</tt> and +Time.json_create+ may be used
- # to serialize and deserialize a \Time object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Time#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/time'
- # x = Time.now.as_json
- # # => {"json_class"=>"Time", "s"=>1700931656, "n"=>472846644}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Time object:
- #
- # Time.json_create(x)
- # # => 2023-11-25 11:00:56.472846644 -0600
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
nanoseconds = [ tv_usec * 1000 ]
respond_to?(:tv_nsec) and nanoseconds << tv_nsec
@@ -44,15 +30,8 @@ class Time
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/time'
- # puts Time.now.to_json
- #
- # Output:
- #
- # {"json_class":"Time","s":1700931678,"n":980650786}
- #
+ # Stores class name (Time) with number of seconds since epoch and number of
+ # microseconds for Time 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 95098d3bb4..ea46896fcc 100644
--- a/ext/json/lib/json/common.rb
+++ b/ext/json/lib/json/common.rb
@@ -1,12 +1,8 @@
#frozen_string_literal: false
require 'json/version'
+require 'json/generic_object'
module JSON
- autoload :GenericObject, 'json/generic_object'
-
- NOT_SET = Object.new.freeze
- private_constant :NOT_SET
-
class << self
# :call-seq:
# JSON[object] -> new_array or new_string
@@ -299,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
@@ -328,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
@@ -576,13 +592,13 @@ module JSON
# Sets or returns the default options for the JSON.dump method.
# Initially:
# opts = JSON.dump_default_options
- # opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
attr_accessor :dump_default_options
end
self.dump_default_options = {
:max_nesting => false,
:allow_nan => true,
- :script_safe => false,
+ :escape_slash => false,
}
# :call-seq:
@@ -612,18 +628,16 @@ module JSON
# puts File.read(path)
# Output:
# {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
- def dump(obj, anIO = nil, limit = nil, kwargs = nil)
- io_limit_opt = [anIO, limit, kwargs].compact
- kwargs = io_limit_opt.pop if io_limit_opt.last.is_a?(Hash)
- anIO, limit = io_limit_opt
- if anIO.respond_to?(:to_io)
- anIO = anIO.to_io
- elsif limit.nil? && !anIO.respond_to?(:write)
- anIO, limit = nil, anIO
+ def dump(obj, anIO = nil, limit = nil)
+ if anIO and limit.nil?
+ anIO = anIO.to_io if anIO.respond_to?(:to_io)
+ unless anIO.respond_to?(:write)
+ limit = anIO
+ anIO = nil
+ end
end
opts = JSON.dump_default_options
opts = opts.merge(:max_nesting => limit) if limit
- opts = merge_dump_options(opts, **kwargs) if kwargs
result = generate(obj, opts)
if anIO
anIO.write result
@@ -639,15 +653,6 @@ module JSON
def self.iconv(to, from, string)
string.encode(to, from)
end
-
- def merge_dump_options(opts, strict: NOT_SET)
- opts = opts.merge(strict: strict) if NOT_SET != strict
- opts
- end
-
- class << self
- private :merge_dump_options
- end
end
module ::Kernel
diff --git a/ext/json/lib/json/generic_object.rb b/ext/json/lib/json/generic_object.rb
index 56efda6495..108309db26 100644
--- a/ext/json/lib/json/generic_object.rb
+++ b/ext/json/lib/json/generic_object.rb
@@ -1,9 +1,5 @@
#frozen_string_literal: false
-begin
- require 'ostruct'
-rescue LoadError
- warn "JSON::GenericObject requires 'ostruct'. Please install it with `gem install ostruct`."
-end
+require 'ostruct'
module JSON
class GenericObject < OpenStruct
@@ -71,5 +67,5 @@ module JSON
def to_json(*a)
as_json.to_json(*a)
end
- end if defined?(::OpenStruct)
+ end
end
diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb
index 836f47edf4..3d4326d836 100644
--- a/ext/json/lib/json/version.rb
+++ b/ext/json/lib/json/version.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: false
module JSON
# JSON version
- VERSION = '2.7.2'
+ VERSION = '2.6.3'
VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
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/parser.c b/ext/json/parser/parser.c
index 57f87432b6..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 - 7);
- }
- }
- 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) {
- ruby_xfree(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) {
- ruby_xfree(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) {
- ruby_xfree(bufferStart);
- }
-# else
- result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
-
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(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 = Qnil;
- 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 af190e7500..2dbdc7ef24 100644
--- a/ext/json/parser/parser.rl
+++ b/ext/json/parser/parser.rl
@@ -229,7 +229,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
if (json->allow_nan) {
*result = CInfinity;
} else {
- rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 7);
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8);
}
}
action parse_string {
@@ -508,7 +508,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
case 'u':
if (pe > stringEnd - 4) {
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
+ free(bufferStart);
}
rb_enc_raise(
EXC_ENCODING eParserError,
@@ -521,7 +521,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
pe++;
if (pe > stringEnd - 6) {
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
+ free(bufferStart);
}
rb_enc_raise(
EXC_ENCODING eParserError,
@@ -566,13 +566,13 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
}
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
+ free(bufferStart);
}
# else
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
+ free(bufferStart);
}
if (intern) {
@@ -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,85 +721,98 @@ 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;
json->create_additions = 0;
- json->create_id = Qnil;
+ json->create_id = rb_funcall(mJSON, i_create_id, 0);
json->object_class = Qnil;
json->array_class = Qnil;
json->decimal_class = Qnil;
@@ -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 85e99a71b4..de5fa6c6a3 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,41 +155,15 @@ 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)/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
-objspace.o: $(hdrdir)/ruby/atomic.h
objspace.o: $(hdrdir)/ruby/backward.h
objspace.o: $(hdrdir)/ruby/backward/2/assume.h
objspace.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -252,7 +215,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 +284,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 +315,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
@@ -372,17 +336,10 @@ objspace.o: $(hdrdir)/ruby/regex.h
objspace.o: $(hdrdir)/ruby/ruby.h
objspace.o: $(hdrdir)/ruby/st.h
objspace.o: $(hdrdir)/ruby/subst.h
-objspace.o: $(hdrdir)/ruby/thread_native.h
-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)/debug_counter.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
-objspace.o: $(top_srcdir)/internal/basic_operators.h
objspace.o: $(top_srcdir)/internal/class.h
objspace.o: $(top_srcdir)/internal/compilers.h
objspace.o: $(top_srcdir)/internal/gc.h
@@ -391,21 +348,10 @@ 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
-objspace.o: $(top_srcdir)/vm_core.h
-objspace.o: $(top_srcdir)/vm_debug.h
-objspace.o: $(top_srcdir)/vm_opts.h
-objspace.o: $(top_srcdir)/vm_sync.h
objspace.o: objspace.c
objspace.o: {$(VPATH)}id.h
objspace_dump.o: $(RUBY_EXTCONF_H)
@@ -464,7 +410,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
@@ -533,6 +478,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
@@ -563,6 +509,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
@@ -588,7 +535,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
@@ -598,7 +545,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
@@ -610,15 +556,11 @@ 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_debug.h
objspace_dump.o: $(top_srcdir)/vm_opts.h
-objspace_dump.o: $(top_srcdir)/vm_sync.h
objspace_dump.o: objspace.h
objspace_dump.o: objspace_dump.c
objspace_dump.o: {$(VPATH)}id.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..0bf866a8f1 100644
--- a/ext/objspace/object_tracing.c
+++ b/ext/objspace/object_tracing.c
@@ -14,7 +14,6 @@
**********************************************************************/
#include "internal.h"
-#include "internal/gc.h"
#include "ruby/debug.h"
#include "objspace.h"
@@ -122,10 +121,6 @@ freeobj_i(VALUE tpval, void *data)
st_data_t v;
struct allocation_info *info;
- /* Modifying the st table can cause allocations, which can trigger GC.
- * Since freeobj_i is called during GC, it must not trigger another GC. */
- VALUE gc_disabled = rb_gc_disable_no_rest();
-
if (arg->keep_remains) {
if (st_lookup(arg->object_table, obj, &v)) {
info = (struct allocation_info *)v;
@@ -140,8 +135,6 @@ freeobj_i(VALUE tpval, void *data)
ruby_xfree(info);
}
}
-
- if (gc_disabled == Qfalse) rb_gc_enable();
}
static int
diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c
index 0a7896d5c6..ca08604c95 100644
--- a/ext/objspace/objspace.c
+++ b/ext/objspace/objspace.c
@@ -12,13 +12,14 @@
**********************************************************************/
+#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"
+#include "node.h"
#include "ruby/io.h"
#include "ruby/re.h"
#include "ruby/st.h"
@@ -336,6 +337,17 @@ count_symbols(int argc, VALUE *argv, VALUE os)
return hash;
}
+static void
+cn_i(VALUE v, void *n)
+{
+ size_t *nodes = (size_t *)n;
+
+ if (BUILTIN_TYPE(v) == T_NODE) {
+ size_t s = nd_type((NODE *)v);
+ nodes[s]++;
+ }
+}
+
/*
* call-seq:
* ObjectSpace.count_nodes([result_hash]) -> hash
@@ -362,7 +374,135 @@ count_symbols(int argc, VALUE *argv, VALUE os)
static VALUE
count_nodes(int argc, VALUE *argv, VALUE os)
{
- return setup_hash(argc, argv);
+ size_t nodes[NODE_LAST+1];
+ enum node_type i;
+ VALUE hash = setup_hash(argc, argv);
+
+ for (i = 0; i <= NODE_LAST; i++) {
+ nodes[i] = 0;
+ }
+
+ each_object_with_flags(cn_i, &nodes[0]);
+
+ for (i=0; i<NODE_LAST; i++) {
+ if (nodes[i] != 0) {
+ VALUE node;
+ switch (i) {
+#define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); goto set
+ COUNT_NODE(NODE_SCOPE);
+ COUNT_NODE(NODE_BLOCK);
+ COUNT_NODE(NODE_IF);
+ COUNT_NODE(NODE_UNLESS);
+ COUNT_NODE(NODE_CASE);
+ COUNT_NODE(NODE_CASE2);
+ COUNT_NODE(NODE_CASE3);
+ COUNT_NODE(NODE_WHEN);
+ COUNT_NODE(NODE_IN);
+ COUNT_NODE(NODE_WHILE);
+ COUNT_NODE(NODE_UNTIL);
+ COUNT_NODE(NODE_ITER);
+ COUNT_NODE(NODE_FOR);
+ COUNT_NODE(NODE_FOR_MASGN);
+ COUNT_NODE(NODE_BREAK);
+ COUNT_NODE(NODE_NEXT);
+ COUNT_NODE(NODE_REDO);
+ COUNT_NODE(NODE_RETRY);
+ COUNT_NODE(NODE_BEGIN);
+ COUNT_NODE(NODE_RESCUE);
+ COUNT_NODE(NODE_RESBODY);
+ COUNT_NODE(NODE_ENSURE);
+ COUNT_NODE(NODE_AND);
+ COUNT_NODE(NODE_OR);
+ COUNT_NODE(NODE_MASGN);
+ COUNT_NODE(NODE_LASGN);
+ COUNT_NODE(NODE_DASGN);
+ COUNT_NODE(NODE_GASGN);
+ COUNT_NODE(NODE_IASGN);
+ COUNT_NODE(NODE_CDECL);
+ COUNT_NODE(NODE_CVASGN);
+ COUNT_NODE(NODE_OP_ASGN1);
+ COUNT_NODE(NODE_OP_ASGN2);
+ COUNT_NODE(NODE_OP_ASGN_AND);
+ COUNT_NODE(NODE_OP_ASGN_OR);
+ COUNT_NODE(NODE_OP_CDECL);
+ COUNT_NODE(NODE_CALL);
+ COUNT_NODE(NODE_OPCALL);
+ COUNT_NODE(NODE_FCALL);
+ COUNT_NODE(NODE_VCALL);
+ COUNT_NODE(NODE_QCALL);
+ COUNT_NODE(NODE_SUPER);
+ 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);
+ COUNT_NODE(NODE_LVAR);
+ COUNT_NODE(NODE_DVAR);
+ COUNT_NODE(NODE_GVAR);
+ COUNT_NODE(NODE_IVAR);
+ COUNT_NODE(NODE_CONST);
+ COUNT_NODE(NODE_CVAR);
+ COUNT_NODE(NODE_NTH_REF);
+ COUNT_NODE(NODE_BACK_REF);
+ COUNT_NODE(NODE_MATCH);
+ COUNT_NODE(NODE_MATCH2);
+ COUNT_NODE(NODE_MATCH3);
+ COUNT_NODE(NODE_LIT);
+ COUNT_NODE(NODE_STR);
+ COUNT_NODE(NODE_DSTR);
+ COUNT_NODE(NODE_XSTR);
+ COUNT_NODE(NODE_DXSTR);
+ COUNT_NODE(NODE_EVSTR);
+ COUNT_NODE(NODE_DREGX);
+ COUNT_NODE(NODE_ONCE);
+ COUNT_NODE(NODE_ARGS);
+ COUNT_NODE(NODE_ARGS_AUX);
+ COUNT_NODE(NODE_OPT_ARG);
+ COUNT_NODE(NODE_KW_ARG);
+ COUNT_NODE(NODE_POSTARG);
+ COUNT_NODE(NODE_ARGSCAT);
+ COUNT_NODE(NODE_ARGSPUSH);
+ COUNT_NODE(NODE_SPLAT);
+ COUNT_NODE(NODE_BLOCK_PASS);
+ COUNT_NODE(NODE_DEFN);
+ COUNT_NODE(NODE_DEFS);
+ COUNT_NODE(NODE_ALIAS);
+ COUNT_NODE(NODE_VALIAS);
+ COUNT_NODE(NODE_UNDEF);
+ COUNT_NODE(NODE_CLASS);
+ COUNT_NODE(NODE_MODULE);
+ COUNT_NODE(NODE_SCLASS);
+ COUNT_NODE(NODE_COLON2);
+ COUNT_NODE(NODE_COLON3);
+ COUNT_NODE(NODE_DOT2);
+ COUNT_NODE(NODE_DOT3);
+ COUNT_NODE(NODE_FLIP2);
+ COUNT_NODE(NODE_FLIP3);
+ COUNT_NODE(NODE_SELF);
+ COUNT_NODE(NODE_NIL);
+ COUNT_NODE(NODE_TRUE);
+ COUNT_NODE(NODE_FALSE);
+ COUNT_NODE(NODE_ERRINFO);
+ COUNT_NODE(NODE_DEFINED);
+ COUNT_NODE(NODE_POSTEXE);
+ COUNT_NODE(NODE_DSYM);
+ COUNT_NODE(NODE_ATTRASGN);
+ COUNT_NODE(NODE_LAMBDA);
+ COUNT_NODE(NODE_ARYPTN);
+ COUNT_NODE(NODE_FNDPTN);
+ COUNT_NODE(NODE_HSHPTN);
+ COUNT_NODE(NODE_ERROR);
+#undef COUNT_NODE
+ case NODE_LAST: break;
+ }
+ UNREACHABLE;
+ set:
+ rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
+ }
+ }
+ return hash;
}
static void
@@ -814,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 1812ba1d08..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[];
@@ -168,8 +166,10 @@ dump_append_c(struct dump_config *dc, unsigned char c)
}
static void
-dump_append_ptr(struct dump_config *dc, VALUE ref)
+dump_append_ref(struct dump_config *dc, VALUE ref)
{
+ RUBY_ASSERT(ref > 0);
+
char buffer[roomof(sizeof(VALUE) * CHAR_BIT, 4) + rb_strlen_lit("\"0x\"")];
char *buffer_start, *buffer_end;
@@ -186,14 +186,6 @@ dump_append_ptr(struct dump_config *dc, VALUE ref)
}
static void
-dump_append_ref(struct dump_config *dc, VALUE ref)
-{
- RUBY_ASSERT(ref > 0);
- dump_append_ptr(dc, ref);
-}
-
-
-static void
dump_append_string_value(struct dump_config *dc, VALUE obj)
{
long i;
@@ -366,9 +358,8 @@ dump_append_string_content(struct dump_config *dc, VALUE obj)
static inline void
dump_append_id(struct dump_config *dc, ID id)
{
- VALUE str = rb_sym2str(ID2SYM(id));
- if (RTEST(str)) {
- dump_append_string_value(dc, str);
+ if (is_instance_id(id)) {
+ dump_append_string_value(dc, rb_sym2str(ID2SYM(id)));
}
else {
dump_append(dc, "\"ID_INTERNAL(");
@@ -386,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);
@@ -438,33 +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_id(dc, mid);
- }
- break;
-
- case imemo_callcache:
- mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id;
- if (mid != 0) {
- dump_append(dc, ", \"called_id\":");
- dump_append_id(dc, mid);
-
- VALUE klass = ((const struct rb_callcache *)obj)->klass;
- if (klass != 0) {
- dump_append(dc, ", \"receiver_class\":");
- dump_append_ref(dc, klass);
- }
- }
- break;
-
- default:
- break;
- }
break;
case T_SYMBOL:
@@ -547,8 +510,9 @@ dump_object(VALUE obj, struct dump_config *dc)
if (dc->cur_obj_klass) {
VALUE mod_name = rb_mod_name(obj);
if (!NIL_P(mod_name)) {
- dump_append(dc, ", \"name\":");
- dump_append_string_value(dc, mod_name);
+ dump_append(dc, ", \"name\":\"");
+ dump_append(dc, RSTRING_PTR(mod_name));
+ dump_append(dc, "\"");
}
else {
VALUE real_mod_name = rb_mod_name(rb_class_real(obj));
@@ -580,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)) {
@@ -791,6 +751,16 @@ shape_i(rb_shape_t *shape, void *data)
case SHAPE_FROZEN:
dump_append(dc, "\"FROZEN\"");
break;
+ case SHAPE_CAPACITY_CHANGE:
+ dump_append(dc, "\"CAPACITY_CHANGE\"");
+ 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 3249f6617a..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
=============
@@ -457,7 +417,7 @@ Security fixes
Bug fixes
---------
-* Fixed OpenSSL::PKey::\*.{new,generate} immediately aborting if the thread is
+* Fixed OpenSSL::PKey::*.{new,generate} immediately aborting if the thread is
interrupted.
[[Bug #14882]](https://bugs.ruby-lang.org/issues/14882)
[[GitHub #205]](https://github.com/ruby/openssl/pull/205)
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..a59849f719 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)
@@ -539,7 +483,7 @@ static VALUE ossl_ec_key_check_key(VALUE self)
#ifdef HAVE_EVP_PKEY_CHECK
EVP_PKEY *pkey;
EVP_PKEY_CTX *pctx;
- const EC_KEY *ec;
+ EC_KEY *ec;
GetPKey(self, pkey);
GetEC(self, ec);
@@ -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 b9e8d9ef11..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.2'
+ 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/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb
index f0fda9bdbc..8614251ca9 100644
--- a/ext/psych/lib/psych/visitors/to_ruby.rb
+++ b/ext/psych/lib/psych/visitors/to_ruby.rb
@@ -101,7 +101,7 @@ module Psych
source = $1
options = 0
lang = nil
- $2&.each_char do |option|
+ ($2 || '').split('').each do |option|
case option
when 'x' then options |= Regexp::EXTENDED
when 'i' then options |= Regexp::IGNORECASE
diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb
index 1dd4094c1d..31858798e4 100644
--- a/ext/psych/lib/psych/visitors/yaml_tree.rb
+++ b/ext/psych/lib/psych/visitors/yaml_tree.rb
@@ -15,29 +15,30 @@ module Psych
class YAMLTree < Psych::Visitors::Visitor
class Registrar # :nodoc:
def initialize
- @obj_to_id = {}.compare_by_identity
- @obj_to_node = {}.compare_by_identity
+ @obj_to_id = {}
+ @obj_to_node = {}
@targets = []
@counter = 0
end
def register target, node
+ return unless target.respond_to? :object_id
@targets << target
- @obj_to_node[target] = node
+ @obj_to_node[target.object_id] = node
end
def key? target
- @obj_to_node.key? target
+ @obj_to_node.key? target.object_id
rescue NoMethodError
false
end
def id_for target
- @obj_to_id[target] ||= (@counter += 1)
+ @obj_to_id[target.object_id] ||= (@counter += 1)
end
def node_for target
- @obj_to_node[target]
+ @obj_to_node[target.object_id]
end
end
@@ -567,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
@@ -575,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 8dca8ba281..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()) {
@@ -745,13 +753,8 @@ void
Init_pty(void)
{
cPTY = rb_define_module("PTY");
-#if 1
- rb_define_module_function(cPTY,"get""pty",pty_getpty,-1);
-#else /* for RDoc */
- /* show getpty as an alias of spawn */
- VALUE sPTY = rb_singleton_class(cPTY);
- rb_define_alias(sPTY, "getpty", "spawn");
-#endif
+ /* :nodoc: */
+ rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
rb_define_module_function(cPTY,"spawn",pty_getpty,-1);
rb_define_singleton_method(cPTY,"check",pty_check,-1);
rb_define_singleton_method(cPTY,"open",pty_open,0);
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 a18b67abe3..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,18 +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: $(hdrdir)/ruby/version.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
@@ -592,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
@@ -601,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
@@ -627,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 a0f1cbeaa8..6a3c04af30 100644
--- a/ext/ripper/lib/ripper/lexer.rb
+++ b/ext/ripper/lib/ripper/lexer.rb
@@ -242,12 +242,7 @@ class Ripper
end
def on_error2(mesg, elem)
- 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
+ @errors.push Elem.new(elem.pos, __callee__, elem.tok, elem.state, mesg)
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 3db153bb1c..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,20 +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: $(hdrdir)/ruby/version.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
@@ -205,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
@@ -275,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
@@ -344,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
@@ -374,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
@@ -393,20 +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: $(hdrdir)/ruby/version.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
@@ -414,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
@@ -484,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
@@ -553,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
@@ -583,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
@@ -602,20 +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: $(hdrdir)/ruby/version.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
@@ -623,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
@@ -694,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
@@ -763,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
@@ -793,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
@@ -812,20 +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: $(hdrdir)/ruby/version.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
@@ -833,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
@@ -903,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
@@ -972,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
@@ -1002,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
@@ -1021,20 +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: $(hdrdir)/ruby/version.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
@@ -1042,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
@@ -1112,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
@@ -1181,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
@@ -1211,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
@@ -1230,20 +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: $(hdrdir)/ruby/version.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
@@ -1251,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
@@ -1321,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
@@ -1390,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
@@ -1420,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
@@ -1439,20 +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: $(hdrdir)/ruby/version.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
@@ -1460,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
@@ -1530,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
@@ -1599,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
@@ -1629,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
@@ -1648,20 +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: $(hdrdir)/ruby/version.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
@@ -1669,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
@@ -1739,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
@@ -1808,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
@@ -1838,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
@@ -1857,20 +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: $(hdrdir)/ruby/version.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
@@ -1878,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
@@ -1948,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
@@ -2017,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
@@ -2047,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
@@ -2066,20 +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: $(hdrdir)/ruby/version.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
@@ -2087,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
@@ -2157,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
@@ -2226,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
@@ -2256,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
@@ -2275,20 +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: $(hdrdir)/ruby/version.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
@@ -2296,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
@@ -2366,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
@@ -2435,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
@@ -2465,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
@@ -2484,20 +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: $(hdrdir)/ruby/version.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
@@ -2505,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
@@ -2575,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
@@ -2644,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
@@ -2674,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
@@ -2693,20 +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: $(hdrdir)/ruby/version.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
@@ -2714,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
@@ -2784,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
@@ -2853,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
@@ -2883,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
@@ -2902,20 +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: $(hdrdir)/ruby/version.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
@@ -2923,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
@@ -2993,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
@@ -3062,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
@@ -3092,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
@@ -3111,20 +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: $(hdrdir)/ruby/version.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
@@ -3132,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 d44ce31b0a..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,10 +687,5 @@ SRC
"not needed"
end
end
-
- have_func("pthread_create")
- have_func("pthread_detach")
-
- $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 dd1158e19d..557d4374a5 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -27,7 +27,6 @@ VALUE rb_cSocket;
VALUE rb_cAddrinfo;
VALUE rb_eSocket;
-VALUE rb_eResolution;
#ifdef SOCKS
VALUE rb_cSOCKSSocket;
@@ -35,10 +34,9 @@ VALUE rb_cSOCKSSocket;
int rsock_do_not_reverse_lookup = 1;
static VALUE sym_wait_readable;
-static ID id_error_code;
void
-rsock_raise_resolution_error(const char *reason, int error)
+rsock_raise_socket_error(const char *reason, int error)
{
#ifdef EAI_SYSTEM
int e;
@@ -50,14 +48,10 @@ rsock_raise_resolution_error(const char *reason, int error)
VALUE msg = rb_sprintf("%s: ", reason);
if (!enc) enc = rb_default_internal_encoding();
rb_str_concat(msg, rb_w32_conv_from_wchar(gai_strerrorW(error), enc));
+ rb_exc_raise(rb_exc_new_str(rb_eSocket, msg));
#else
- VALUE msg = rb_sprintf("%s: %s", reason, gai_strerror(error));
+ rb_raise(rb_eSocket, "%s: %s", reason, gai_strerror(error));
#endif
-
- StringValue(msg);
- VALUE self = rb_class_new_instance(1, &msg, rb_eResolution);
- rb_ivar_set(self, id_error_code, INT2NUM(error));
- rb_exc_raise(self);
}
#if defined __APPLE__
@@ -122,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;
@@ -154,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)
{
@@ -206,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))
@@ -281,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) {
@@ -418,7 +392,7 @@ rsock_write_nonblock(VALUE sock, VALUE str, VALUE ex)
if (e == EWOULDBLOCK || e == EAGAIN) {
if (ex == Qfalse) return sym_wait_writable;
rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e,
- "write would block");
+ "write would block");
}
rb_syserr_fail_path(e, fptr->pathv);
}
@@ -459,9 +433,9 @@ rsock_socket(int domain, int type, int proto)
fd = rsock_socket0(domain, type, proto);
if (fd < 0) {
- if (rb_gc_for_fd(errno)) {
- fd = rsock_socket0(domain, type, proto);
- }
+ if (rb_gc_for_fd(errno)) {
+ fd = rsock_socket0(domain, type, proto);
+ }
}
if (0 <= fd)
rb_update_max_fd(fd);
@@ -518,10 +492,10 @@ wait_connectable(int fd, struct timeval *timeout)
switch (sockerr) {
case 0:
- /*
- * be defensive in case some platforms set SO_ERROR on the original,
- * interrupted connect()
- */
+ /*
+ * be defensive in case some platforms set SO_ERROR on the original,
+ * interrupted connect()
+ */
/* when the connection timed out, no errno is set and revents is 0. */
if (timeout && revents == 0) {
@@ -707,9 +681,9 @@ rsock_s_accept(VALUE klass, VALUE io, struct sockaddr *sockaddr, socklen_t *len)
RB_IO_POINTER(io, fptr);
struct accept_arg accept_arg = {
- .fd = fptr->fd,
- .sockaddr = sockaddr,
- .len = len
+ .fd = fptr->fd,
+ .sockaddr = sockaddr,
+ .len = len
};
int retry = 0, peer;
@@ -756,10 +730,10 @@ rsock_getfamily(rb_io_t *fptr)
if (cached) {
switch (cached) {
#ifdef AF_UNIX
- case FMODE_UNIX: return AF_UNIX;
+ case FMODE_UNIX: return AF_UNIX;
#endif
- case FMODE_INET: return AF_INET;
- case FMODE_INET6: return AF_INET6;
+ case FMODE_INET: return AF_INET;
+ case FMODE_INET6: return AF_INET6;
}
}
@@ -778,18 +752,6 @@ rsock_getfamily(rb_io_t *fptr)
return ss.addr.sa_family;
}
-/*
- * call-seq:
- * error_code -> integer
- *
- * Returns the raw error code occurred at name resolution.
- */
-static VALUE
-sock_resolv_error_code(VALUE self)
-{
- return rb_attr_get(self, id_error_code);
-}
-
void
rsock_init_socket_init(void)
{
@@ -797,11 +759,6 @@ rsock_init_socket_init(void)
* SocketError is the error class for socket.
*/
rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
- /*
- * ResolutionError is the error class for socket name resolution.
- */
- rb_eResolution = rb_define_class_under(rb_cSocket, "ResolutionError", rb_eSocket);
- rb_define_method(rb_eResolution, "error_code", sock_resolv_error_code, 0);
rsock_init_ipsocket();
rsock_init_tcpsocket();
rsock_init_tcpserver();
@@ -815,8 +772,6 @@ rsock_init_socket_init(void)
rsock_init_sockifaddr();
rsock_init_socket_constants();
- id_error_code = rb_intern_const("error_code");
-
#undef rb_intern
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index de542223c6..eecdc7d4b8 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -333,10 +333,9 @@ class BasicSocket < IO
# _flags_ is zero or more of the +MSG_+ options.
# The result, _mesg_, is the data received.
#
- # When recvfrom(2) returns 0, Socket#recv_nonblock returns nil.
- # In most cases it means the connection was closed, but for UDP connections
- # it may mean an empty packet was received, as the underlying API makes
- # it impossible to distinguish these two cases.
+ # When recvfrom(2) returns 0, Socket#recv_nonblock returns
+ # an empty string as data.
+ # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
#
# === Parameters
# * +maxlen+ - the number of bytes to receive from the socket
@@ -481,10 +480,9 @@ class Socket < BasicSocket
# The second element, _sender_addrinfo_, contains protocol-specific address
# information of the sender.
#
- # When recvfrom(2) returns 0, Socket#recv_nonblock returns nil.
- # In most cases it means the connection was closed, but for UDP connections
- # it may mean an empty packet was received, as the underlying API makes
- # it impossible to distinguish these two cases.
+ # When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
+ # an empty string as data.
+ # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
#
# === Parameters
# * +maxlen+ - the maximum number of bytes to receive from the socket
@@ -1231,10 +1229,9 @@ class UDPSocket < IPSocket
# The first element of the results, _mesg_, is the data received.
# The second element, _sender_inet_addr_, is an array to represent the sender address.
#
- # When recvfrom(2) returns 0, Socket#recv_nonblock returns nil.
- # In most cases it means the connection was closed, but it may also mean
- # an empty packet was received, as the underlying API makes
- # it impossible to distinguish these two cases.
+ # When recvfrom(2) returns 0,
+ # Socket#recvfrom_nonblock returns an empty string as data.
+ # It means an empty packet.
#
# === Parameters
# * +maxlen+ - the number of bytes to receive from the socket
diff --git a/ext/socket/mkconstants.rb b/ext/socket/mkconstants.rb
index ba7a55b426..5e6c0668f6 100644
--- a/ext/socket/mkconstants.rb
+++ b/ext/socket/mkconstants.rb
@@ -51,10 +51,7 @@ DATA.each_line {|s|
next
end
h[name] = default_value
- if comment
- # Stop unintentional references
- COMMENTS[name] = comment.gsub(/\b(Data|Kernel|Process|Set|Socket|Time)\b/, '\\\\\\&')
- end
+ COMMENTS[name] = comment
}
DEFS = h.to_a
@@ -426,8 +423,8 @@ AF_ISDN nil Integrated Services Digital Network
PF_ISDN nil Integrated Services Digital Network
AF_NATM nil Native ATM access
PF_NATM nil Native ATM access
-AF_SYSTEM nil Kernel event messages
-PF_SYSTEM nil Kernel event messages
+AF_SYSTEM
+PF_SYSTEM
AF_NETBIOS nil NetBIOS
PF_NETBIOS nil NetBIOS
AF_PPP nil Point-to-Point Protocol
@@ -443,8 +440,8 @@ PF_PACKET nil Direct link-layer access
AF_E164 nil CCITT (ITU-T) E.164 recommendation
PF_XTP nil eXpress Transfer Protocol
-PF_RTIP nil Help Identify RTIP packets
-PF_PIP nil Help Identify PIP packets
+PF_RTIP
+PF_PIP
AF_KEY nil Key management protocol, originally developed for usage with IPsec
PF_KEY nil Key management protocol, originally developed for usage with IPsec
AF_NETLINK nil Kernel user interface device
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index 909c02752c..269edc4dad 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,9 +287,8 @@ numeric_getaddrinfo(const char *node, const char *service,
void
rb_freeaddrinfo(struct rb_addrinfo *ai)
{
- if (!ai->allocated_by_malloc) {
- if (ai->ai) freeaddrinfo(ai->ai);
- }
+ if (!ai->allocated_by_malloc)
+ freeaddrinfo(ai->ai);
else {
struct addrinfo *ai1, *ai2;
ai1 = ai->ai;
@@ -293,263 +302,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, gai_errno, 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, gai_errno;
- err = getaddrinfo(arg->node, arg->service, &arg->hints, &arg->ai);
- gai_errno = errno;
-#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;
- arg->gai_errno = gai_errno;
- if (arg->cancelled) {
- if (arg->ai) 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
-do_pthread_create(pthread_t *th, void *(*start_routine) (void *), void *arg)
-{
- int limit = 3, ret;
- do {
- // It is said that pthread_create may fail spuriously, so we follow the JDK and retry several times.
- //
- // https://bugs.openjdk.org/browse/JDK-8268605
- // https://github.com/openjdk/jdk/commit/e35005d5ce383ddd108096a3079b17cb0bcf76f1
- ret = pthread_create(th, 0, start_routine, arg);
- } while (ret == EAGAIN && limit-- > 0);
- return ret;
-}
-
-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, gai_errno = 0;
-
-start:
- retry = 0;
-
- arg = allocate_getaddrinfo_arg(hostp, portp, hints);
- if (!arg) {
- return EAI_MEMORY;
- }
-
- pthread_t th;
- if (do_pthread_create(&th, 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;
- gai_errno = arg->gai_errno;
- if (err == 0) *ai = arg->ai;
- }
- else if (arg->cancelled) {
- retry = 1;
- }
- 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;
-
- /* Because errno is threadlocal, the errno value we got from the call to getaddrinfo() in the thread
- * (in case of EAI_SYSTEM return value) is not propagated to the caller of _this_ function. Set errno
- * explicitly, as round-tripped through struct getaddrinfo_arg, to deal with that */
- if (gai_errno) errno = gai_errno;
- 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;
@@ -570,11 +323,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;
@@ -586,176 +344,8 @@ 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, gni_errno, 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, gni_errno;
- err = getnameinfo(arg->sa, arg->salen, arg->host, (socklen_t)arg->hostlen, arg->serv, (socklen_t)arg->servlen, arg->flags);
- gni_errno = errno;
-
- int need_free = 0;
- rb_nativethread_lock_lock(&arg->lock);
- arg->err = err;
- arg->gni_errno = gni_errno;
- 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, gni_errno = 0;
-
-start:
- retry = 0;
-
- arg = allocate_getnameinfo_arg(sa, salen, hostlen, servlen, flags);
- if (!arg) {
- return EAI_MEMORY;
- }
-
- pthread_t th;
- if (do_pthread_create(&th, 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;
- gni_errno = arg->gni_errno;
- if (err == 0) {
- if (host) memcpy(host, arg->host, hostlen);
- if (serv) memcpy(serv, arg->serv, servlen);
- }
- }
- else if (arg->cancelled) {
- retry = 1;
- }
- 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;
-
- /* Make sure we copy the thread-local errno value from the getnameinfo thread back to this thread, so
- * calling code sees the correct errno */
- if (gni_errno) errno = gni_errno;
- return err;
-}
-
#endif
+}
static void
make_ipaddr0(struct sockaddr *addr, socklen_t addrlen, char *buf, size_t buflen)
@@ -764,7 +354,7 @@ make_ipaddr0(struct sockaddr *addr, socklen_t addrlen, char *buf, size_t buflen)
error = rb_getnameinfo(addr, addrlen, buf, buflen, NULL, 0, NI_NUMERICHOST);
if (error) {
- rsock_raise_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
}
@@ -960,7 +550,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;
@@ -973,7 +573,7 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
if (hostp && hostp[strlen(hostp)-1] == '\n') {
rb_raise(rb_eSocket, "newline at the end of hostname");
}
- rsock_raise_resolution_error("getaddrinfo", error);
+ rsock_raise_socket_error("getaddrinfo", error);
}
return res;
@@ -1032,7 +632,7 @@ rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
error = rb_getnameinfo(sockaddr, sockaddrlen, hbuf, sizeof(hbuf),
pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (error) {
- rsock_raise_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
addr2 = rb_str_new2(hbuf);
if (addr1 == Qnil) {
@@ -1666,11 +1266,11 @@ 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_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
if (addr->sin6_port == 0) {
rb_str_cat2(ret, hbuf);
@@ -2034,11 +1634,11 @@ 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_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
sockaddr = rb_assoc_new(rb_str_new_cstr(hbuf), rb_str_new_cstr(pbuf));
break;
@@ -2380,11 +1980,11 @@ 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_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
@@ -3014,12 +2614,12 @@ rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
void
rsock_init_addrinfo(void)
{
- id_timeout = rb_intern("timeout");
-
/*
* The Addrinfo class maps <tt>struct addrinfo</tt> to ruby. This
* structure identifies an Internet host and a service.
*/
+ id_timeout = rb_intern("timeout");
+
rb_cAddrinfo = rb_define_class("Addrinfo", rb_cObject);
rb_define_alloc_func(rb_cAddrinfo, addrinfo_s_allocate);
rb_define_method(rb_cAddrinfo, "initialize", addrinfo_initialize, -1);
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 283735b12c..5f803ba0da 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -285,7 +285,6 @@ extern VALUE rb_cAddrinfo;
extern VALUE rb_cSockOpt;
extern VALUE rb_eSocket;
-extern VALUE rb_eResolution;
#ifdef SOCKS
extern VALUE rb_cSOCKSSocket;
@@ -308,7 +307,7 @@ VALUE rsock_sockaddr_string_value_with_addrinfo(volatile VALUE *v, VALUE *ai_ret
VALUE rb_check_sockaddr_string_type(VALUE);
-NORETURN(void rsock_raise_resolution_error(const char *, int));
+NORETURN(void rsock_raise_socket_error(const char *, int));
int rsock_family_arg(VALUE domain);
int rsock_socktype_arg(VALUE type);
@@ -460,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 c780d77cf6..eb74f7a936 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -1313,7 +1313,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
saved_errno = errno;
if (res) rb_freeaddrinfo(res);
errno = saved_errno;
- rsock_raise_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
UNREACHABLE_RETURN(Qnil);
}
@@ -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 553732f79c..a933159766 100644
--- a/ext/stringio/extconf.rb
+++ b/ext/stringio/extconf.rb
@@ -1,7 +1,4 @@
# frozen_string_literal: false
require 'mkmf'
-if RUBY_ENGINE == 'ruby'
- create_makefile('stringio')
-else
- File.write('Makefile', dummy_makefile("").join)
-end
+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 74e2b95c99..0054766dac 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -12,8 +12,7 @@
**********************************************************************/
-static const char *const
-STRINGIO_VERSION = "3.1.1";
+#define STRINGIO_VERSION "3.0.4"
#include "ruby.h"
#include "ruby/io.h"
@@ -33,6 +32,86 @@ STRINGIO_VERSION = "3.1.1";
# 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..b53b63e455 100644
--- a/ext/strscan/extconf.rb
+++ b/ext/strscan/extconf.rb
@@ -3,7 +3,6 @@ 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")
create_makefile 'strscan'
else
File.write('Makefile', dummy_makefile("").join)
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index 4598d13c90..9b646ab678 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.9"
+#define STRSCAN_VERSION "3.0.5"
/* =======================================================================
Data Type Definitions
@@ -539,68 +539,6 @@ adjust_register_position(struct strscanner *p, long position)
}
}
-/* rb_reg_onig_match is available in Ruby 3.3 and later. */
-#ifndef HAVE_RB_REG_ONIG_MATCH
-static 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 *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) {
- if (RREGEXP(re)->usecnt) {
- onig_free(reg);
- }
- else {
- onig_free(RREGEXP_PTR(re));
- RREGEXP_PTR(re) = reg;
- }
- }
-
- if (result < 0) {
- if (result != ONIG_MISMATCH) {
- rb_raise(ScanError, "regexp buffer overflow");
- }
- }
-
- return result;
-}
-#endif
-
-static OnigPosition
-strscan_match(regex_t *reg, VALUE str, struct re_registers *regs, void *args_ptr)
-{
- struct strscanner *p = (struct strscanner *)args_ptr;
-
- return onig_match(reg,
- match_target(p),
- (UChar* )(CURPTR(p) + S_RESTLEN(p)),
- (UChar* )CURPTR(p),
- regs,
- ONIG_OPTION_NONE);
-}
-
-static OnigPosition
-strscan_search(regex_t *reg, VALUE str, struct re_registers *regs, void *args_ptr)
-{
- struct strscanner *p = (struct strscanner *)args_ptr;
-
- return onig_search(reg,
- match_target(p),
- (UChar *)(CURPTR(p) + S_RESTLEN(p)),
- (UChar *)CURPTR(p),
- (UChar *)(CURPTR(p) + S_RESTLEN(p)),
- regs,
- ONIG_OPTION_NONE);
-}
-
static VALUE
strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly)
{
@@ -622,14 +560,47 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly
}
if (RB_TYPE_P(pattern, T_REGEXP)) {
+ regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
+ regex_t *re;
+ long ret;
+ int tmpreg;
+
p->regex = pattern;
- OnigPosition ret = rb_reg_onig_match(pattern,
- p->str,
- headonly ? strscan_match : strscan_search,
- (void *)p,
- &(p->regs));
+ re = rb_reg_prepare_re(pattern, p->str);
+ tmpreg = re != RREGEXP_PTR(pattern);
+ if (!tmpreg) RREGEXP(pattern)->usecnt++;
+
+ if (headonly) {
+ ret = onig_match(re,
+ match_target(p),
+ (UChar* )(CURPTR(p) + S_RESTLEN(p)),
+ (UChar* )CURPTR(p),
+ &(p->regs),
+ ONIG_OPTION_NONE);
+ }
+ else {
+ ret = onig_search(re,
+ match_target(p),
+ (UChar* )(CURPTR(p) + S_RESTLEN(p)),
+ (UChar* )CURPTR(p),
+ (UChar* )(CURPTR(p) + S_RESTLEN(p)),
+ &(p->regs),
+ ONIG_OPTION_NONE);
+ }
+ if (!tmpreg) RREGEXP(pattern)->usecnt--;
+ if (tmpreg) {
+ if (RREGEXP(pattern)->usecnt) {
+ onig_free(re);
+ }
+ else {
+ onig_free(RREGEXP_PTR(pattern));
+ RREGEXP_PTR(pattern) = re;
+ }
+ }
- if (ret == ONIG_MISMATCH) {
+ if (ret == -2) rb_raise(ScanError, "regexp buffer overflow");
+ if (ret < 0) {
+ /* not matched */
return Qnil;
}
}
@@ -1067,9 +1038,8 @@ strscan_empty_p(VALUE self)
* This method is obsolete; use #eos? instead.
*
* s = StringScanner.new('test string')
- * # These two are opposites
- * s.eos? # => false
- * s.rest? # => true
+ * s.eos? # These two
+ * s.rest? # are opposites.
*/
static VALUE
strscan_rest_p(VALUE self)
@@ -1243,10 +1213,10 @@ strscan_size(VALUE self)
* If nothing was priorly matched, it returns nil.
*
* s = StringScanner.new("Fri Dec 12 1975 14:39")
- * s.scan(/(\w+) (\w+) (\d+) (1980)?/) # -> "Fri Dec 12 "
- * s.captures # -> ["Fri", "Dec", "12", nil]
- * s.scan(/(\w+) (\w+) (\d+) (1980)?/) # -> nil
- * s.captures # -> nil
+ * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 "
+ * s.captures # -> ["Fri", "Dec", "12"]
+ * s.scan(/(\w+) (\w+) (\d+) /) # -> nil
+ * s.captures # -> nil
*/
static VALUE
strscan_captures(VALUE self)
@@ -1262,13 +1232,9 @@ strscan_captures(VALUE self)
new_ary = rb_ary_new2(num_regs);
for (i = 1; i < num_regs; i++) {
- VALUE str;
- if (p->regs.beg[i] == -1)
- str = Qnil;
- else
- str = extract_range(p,
- adjust_register_position(p, p->regs.beg[i]),
- adjust_register_position(p, p->regs.end[i]));
+ VALUE str = extract_range(p,
+ adjust_register_position(p, p->regs.beg[i]),
+ adjust_register_position(p, p->regs.end[i]));
rb_ary_push(new_ary, str);
}
@@ -1535,9 +1501,7 @@ strscan_named_captures(VALUE self)
named_captures_data data;
data.self = self;
data.captures = rb_hash_new();
- if (!RB_NIL_P(p->regex)) {
- onig_foreach_name(RREGEXP_PTR(p->regex), named_captures_iter, &data);
- }
+ onig_foreach_name(RREGEXP_PTR(p->regex), named_captures_iter, &data);
return data.captures;
}
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 4fbbb2ec6e..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.2"
-
/* 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 bda8bb012f..b5b99ff684 100644
--- a/ext/win32/lib/win32/registry.rb
+++ b/ext/win32/lib/win32/registry.rb
@@ -69,11 +69,7 @@ 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
- begin
- LOCALE = Encoding.find(Encoding.locale_charmap)
- rescue ArgumentError
- LOCALE = Encoding::UTF_8
- end
+ LOCALE = Encoding.find(Encoding.locale_charmap)
class Registry
@@ -744,11 +740,14 @@ 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) << WCHAR_NUL
+ data = data.encode(WCHAR)
+ termsize = WCHAR_SIZE
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
@@ -760,7 +759,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)
+ API.SetValue(@hkey, name, type, data, data.bytesize + termsize)
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 3db4d25271..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.1"
+#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);
}
}
@@ -3500,9 +3500,6 @@ static VALUE
rb_gzfile_eof_p(VALUE obj)
{
struct gzfile *gz = get_gzfile(obj);
- while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) == 0) {
- gzfile_read_more(gz, Qnil);
- }
return GZFILE_IS_FINISHED(gz) ? Qtrue : Qfalse;
}
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 373788b206..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)
@@ -483,29 +484,28 @@ apply2files(int (*func)(const char *, void *), int argc, VALUE *argv, void *arg)
return LONG2FIX(argc);
}
+static size_t
+stat_memsize(const void *p)
+{
+ return sizeof(struct stat);
+}
+
static const rb_data_type_t stat_data_type = {
"stat",
- {
- NULL,
- RUBY_TYPED_DEFAULT_FREE,
- NULL, // No external memory to report
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
-};
-
-struct rb_stat {
- struct stat stat;
- bool initialized;
+ {NULL, RUBY_TYPED_DEFAULT_FREE, stat_memsize,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
stat_new_0(VALUE klass, const struct stat *st)
{
- struct rb_stat *rb_st;
- VALUE obj = TypedData_Make_Struct(klass, struct rb_stat, &stat_data_type, rb_st);
+ struct stat *nst = 0;
+ VALUE obj = TypedData_Wrap_Struct(klass, &stat_data_type, 0);
+
if (st) {
- rb_st->stat = *st;
- rb_st->initialized = true;
+ nst = ALLOC(struct stat);
+ *nst = *st;
+ RTYPEDDATA_DATA(obj) = nst;
}
return obj;
}
@@ -519,10 +519,10 @@ rb_stat_new(const struct stat *st)
static struct stat*
get_stat(VALUE self)
{
- struct rb_stat* rb_st;
- TypedData_Get_Struct(self, struct rb_stat, &stat_data_type, rb_st);
- if (!rb_st->initialized) rb_raise(rb_eTypeError, "uninitialized File::Stat");
- return &rb_st->stat;
+ struct stat* st;
+ TypedData_Get_Struct(self, struct stat, &stat_data_type, st);
+ if (!st) rb_raise(rb_eTypeError, "uninitialized File::Stat");
+ return st;
}
static struct timespec stat_mtimespec(const struct stat *st);
@@ -964,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:
@@ -1093,9 +1093,9 @@ rb_stat_inspect(VALUE self)
#endif
};
- struct rb_stat* rb_st;
- TypedData_Get_Struct(self, struct rb_stat, &stat_data_type, rb_st);
- if (!rb_st->initialized) {
+ struct stat* st;
+ TypedData_Get_Struct(self, struct stat, &stat_data_type, st);
+ if (!st) {
return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
}
@@ -1189,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;
@@ -1289,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)
@@ -1479,7 +1478,7 @@ rb_group_member(GETGROUPS_T gid)
ALLOCV_END(v);
return rv;
-#endif /* defined(_WIN32) || !defined(HAVE_GETGROUPS) */
+#endif
}
#ifndef S_IXUGO
@@ -1530,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;
@@ -1594,6 +1593,8 @@ rb_access(VALUE fname, int mode)
*/
/*
+ * Document-method: directory?
+ *
* call-seq:
* File.directory?(path) -> true or false
*
@@ -1772,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
*
*/
@@ -2453,7 +2454,6 @@ rb_file_ctime(VALUE obj)
return stat_ctime(&st);
}
-#if defined(HAVE_STAT_BIRTHTIME)
/*
* call-seq:
* File.birthtime(file_name) -> time
@@ -2468,6 +2468,7 @@ rb_file_ctime(VALUE obj)
*
*/
+#if defined(HAVE_STAT_BIRTHTIME)
RUBY_FUNC_EXPORTED VALUE
rb_file_s_birthtime(VALUE klass, VALUE fname)
{
@@ -2513,6 +2514,16 @@ rb_file_birthtime(VALUE obj)
# define rb_file_birthtime rb_f_notimplement
#endif
+/*
+ * call-seq:
+ * file.size -> integer
+ *
+ * Returns the size of <i>file</i> in bytes.
+ *
+ * File.new("testfile").size #=> 66
+ *
+ */
+
rb_off_t
rb_file_size(VALUE file)
{
@@ -2536,16 +2547,6 @@ rb_file_size(VALUE file)
}
}
-/*
- * call-seq:
- * file.size -> integer
- *
- * Returns the size of <i>file</i> in bytes.
- *
- * File.new("testfile").size #=> 66
- *
- */
-
static VALUE
file_size(VALUE self)
{
@@ -2835,7 +2836,7 @@ utime_failed(struct apply_arg *aa)
}
rb_syserr_fail_path(e, path);
}
-#endif /* UTIME_EINVAL */
+#endif
#if defined(HAVE_UTIMES)
@@ -2859,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)
@@ -2873,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) {
@@ -2896,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;
@@ -2919,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 {
@@ -2941,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)
@@ -3312,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
@@ -3332,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
@@ -3400,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)
@@ -3445,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;
}
@@ -3540,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;\
@@ -3645,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)
{
@@ -3675,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)) {
@@ -3690,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 `~'");
}
@@ -3820,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);
@@ -3840,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 {
@@ -3893,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__
@@ -3918,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__
@@ -3943,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;
}
@@ -3967,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);
}
@@ -3989,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;
@@ -4013,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);
@@ -4030,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;
@@ -4078,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)
@@ -4325,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);
@@ -4494,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)) {
@@ -4512,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;
@@ -4609,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
@@ -4649,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))) {
@@ -4897,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)) {
@@ -4970,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"
*
*/
@@ -5222,75 +5222,47 @@ rb_thread_flock(void *data)
return (VALUE)ret;
}
-/* :markup: markdown
- *
+/*
* call-seq:
- * flock(locking_constant) -> 0 or false
- *
- * Locks or unlocks a file according to the given `locking_constant`,
- * a bitwise OR of the values in the table below.
+ * file.flock(locking_constant) -> 0 or false
+ *
+ * Locks or unlocks a file according to <i>locking_constant</i> (a
+ * logical <em>or</em> of the values in the table below).
+ * Returns <code>false</code> if File::LOCK_NB is specified and the
+ * operation would otherwise have blocked. Not available on all
+ * platforms.
+ *
+ * Locking constants (in class File):
+ *
+ * LOCK_EX | Exclusive lock. Only one process may hold an
+ * | exclusive lock for a given file at a time.
+ * ----------+------------------------------------------------
+ * LOCK_NB | Don't block when locking. May be combined
+ * | with other lock options using logical or.
+ * ----------+------------------------------------------------
+ * LOCK_SH | Shared lock. Multiple processes may each hold a
+ * | shared lock for a given file at the same time.
+ * ----------+------------------------------------------------
+ * LOCK_UN | Unlock.
*
- * Not available on all platforms.
- *
- * Returns `false` if `File::LOCK_NB` is specified and the operation would have blocked;
- * otherwise returns `0`.
- * <br>
- *
- * <table>
- * <tr>
- * <th colspan="3">Locking Constants</th>
- * </tr>
- * <tr>
- * <th>Constant</th>
- * <th>Lock</th>
- * <th>Effect</th>
- * </tr>
- * <tr>
- * <td><tt>File::LOCK_EX</tt></td>
- * <td>Exclusive</td>
- * <td>Only one process may hold an exclusive lock for <tt>self</tt> at a time.</td>
- * </tr>
- * <tr>
- * <td><tt>File::LOCK_NB</tt></td>
- * <td>Non-blocking</td>
- * <td>
- * No blocking; may be combined with other <tt>File::LOCK_SH</tt> or <tt>File::LOCK_EX</tt>
- * using the bitwise OR operator <tt>|</tt>.
- * </td>
- * </tr>
- * <tr>
- * <td><tt>File::LOCK_SH</tt></td>
- * <td>Shared</td>
- * <td>Multiple processes may each hold a shared lock for <tt>self</tt> at the same time.</td>
- * </tr>
- * <tr>
- * <td><tt>File::LOCK_UN</tt></td>
- * <td>Unlock</td>
- * <td>Remove an existing lock held by this process.</td>
- * </tr>
- * </table>
- *
- * <br>
* Example:
*
- * ```ruby
- * # Update a counter using an exclusive lock.
- * # Don't use File::WRONLY because it truncates the file.
- * File.open('counter', File::RDWR | File::CREAT, 0644) do |f|
- * f.flock(File::LOCK_EX)
- * value = f.read.to_i + 1
- * f.rewind
- * f.write("#{value}\n")
- * f.flush
- * f.truncate(f.pos)
- * end
- *
- * # Read the counter using a shared lock.
- * File.open('counter', 'r') do |f|
- * f.flock(File::LOCK_SH)
- * f.read
- * end
- * ```
+ * # update a counter using write lock
+ * # don't use "w" because it truncates the file before lock.
+ * File.open("counter", File::RDWR|File::CREAT, 0644) {|f|
+ * f.flock(File::LOCK_EX)
+ * value = f.read.to_i + 1
+ * f.rewind
+ * f.write("#{value}\n")
+ * f.flush
+ * f.truncate(f.pos)
+ * }
+ *
+ * # read the counter using read lock
+ * File.open("counter", "r") {|f|
+ * f.flock(File::LOCK_SH)
+ * p f.read
+ * }
*
*/
@@ -5586,7 +5558,7 @@ rb_stat_s_alloc(VALUE klass)
static VALUE
rb_stat_init(VALUE obj, VALUE fname)
{
- struct stat st;
+ struct stat st, *nst;
FilePathValue(fname);
fname = rb_str_encode_ospath(fname);
@@ -5594,11 +5566,13 @@ rb_stat_init(VALUE obj, VALUE fname)
rb_sys_fail_path(fname);
}
- struct rb_stat *rb_st;
- TypedData_Get_Struct(obj, struct rb_stat, &stat_data_type, rb_st);
-
- rb_st->stat = st;
- rb_st->initialized = true;
+ if (DATA_PTR(obj)) {
+ xfree(DATA_PTR(obj));
+ DATA_PTR(obj) = NULL;
+ }
+ nst = ALLOC(struct stat);
+ *nst = st;
+ DATA_PTR(obj) = nst;
return Qnil;
}
@@ -5607,15 +5581,19 @@ rb_stat_init(VALUE obj, VALUE fname)
static VALUE
rb_stat_init_copy(VALUE copy, VALUE orig)
{
- if (!OBJ_INIT_COPY(copy, orig)) return copy;
-
- struct rb_stat *orig_rb_st;
- TypedData_Get_Struct(orig, struct rb_stat, &stat_data_type, orig_rb_st);
+ struct stat *nst;
- struct rb_stat *copy_rb_st;
- TypedData_Get_Struct(copy, struct rb_stat, &stat_data_type, copy_rb_st);
+ if (!OBJ_INIT_COPY(copy, orig)) return copy;
+ if (DATA_PTR(copy)) {
+ xfree(DATA_PTR(copy));
+ DATA_PTR(copy) = 0;
+ }
+ if (DATA_PTR(orig)) {
+ nst = ALLOC(struct stat);
+ *nst = *(struct stat*)DATA_PTR(orig);
+ DATA_PTR(copy) = nst;
+ }
- *copy_rb_st = *orig_rb_st;
return copy;
}
@@ -5899,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;
}
/*
@@ -5985,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;
}
/*
@@ -6107,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
*
*/
@@ -6390,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);
@@ -6552,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:
*
@@ -6560,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].
@@ -7155,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:
@@ -7200,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>.
*
@@ -7210,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:
@@ -7255,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_
@@ -7452,396 +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
- *
- * 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
+ * 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::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);
- /* {File::RDONLY}[rdoc-ref:File::Constants@File-3A-3ARDONLY] */
+
+ /* open for reading only */
rb_define_const(rb_mFConst, "RDONLY", INT2FIX(O_RDONLY));
- /* {File::WRONLY}[rdoc-ref:File::Constants@File-3A-3AWRONLY] */
+ /* open for writing only */
rb_define_const(rb_mFConst, "WRONLY", INT2FIX(O_WRONLY));
- /* {File::RDWR}[rdoc-ref:File::Constants@File-3A-3ARDWR] */
+ /* open for reading and writing */
rb_define_const(rb_mFConst, "RDWR", INT2FIX(O_RDWR));
- /* {File::APPEND}[rdoc-ref:File::Constants@File-3A-3AAPPEND] */
+ /* append on each write */
rb_define_const(rb_mFConst, "APPEND", INT2FIX(O_APPEND));
- /* {File::CREAT}[rdoc-ref:File::Constants@File-3A-3ACREAT] */
+ /* create file if it does not exist */
rb_define_const(rb_mFConst, "CREAT", INT2FIX(O_CREAT));
- /* {File::EXCL}[rdoc-ref:File::Constants@File-3A-3AEXCL] */
+ /* 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
- /* {File::NONBLOCK}[rdoc-ref:File::Constants@File-3A-3ANONBLOCK] */
+ /* do not block on open or for data to become available */
rb_define_const(rb_mFConst, "NONBLOCK", INT2FIX(O_NONBLOCK));
#endif
- /* {File::TRUNC}[rdoc-ref:File::Constants@File-3A-3ATRUNC] */
+ /* truncate size to 0 */
rb_define_const(rb_mFConst, "TRUNC", INT2FIX(O_TRUNC));
#ifdef O_NOCTTY
- /* {File::NOCTTY}[rdoc-ref:File::Constants@File-3A-3ANOCTTY] */
+ /* 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
- /* {File::BINARY}[rdoc-ref:File::Constants@File-3A-3ABINARY] */
+ /* disable line code conversion */
rb_define_const(rb_mFConst, "BINARY", INT2FIX(O_BINARY));
#ifndef O_SHARE_DELETE
# define O_SHARE_DELETE 0
#endif
- /* {File::SHARE_DELETE}[rdoc-ref:File::Constants@File-3A-3ASHARE_DELETE+-28Windows+Only-29] */
+ /* can delete opened file */
rb_define_const(rb_mFConst, "SHARE_DELETE", INT2FIX(O_SHARE_DELETE));
#ifdef O_SYNC
- /* {File::SYNC}[rdoc-ref:File::Constants@File-3A-3ASYNC-2C+File-3A-3ARSYNC-2C+and+File-3A-3ADSYNC] */
+ /* any write operation perform synchronously */
rb_define_const(rb_mFConst, "SYNC", INT2FIX(O_SYNC));
#endif
#ifdef O_DSYNC
- /* {File::DSYNC}[rdoc-ref:File::Constants@File-3A-3ASYNC-2C+File-3A-3ARSYNC-2C+and+File-3A-3ADSYNC] */
+ /* any write operation perform synchronously except some meta data */
rb_define_const(rb_mFConst, "DSYNC", INT2FIX(O_DSYNC));
#endif
#ifdef O_RSYNC
- /* {File::RSYNC}[rdoc-ref:File::Constants@File-3A-3ASYNC-2C+File-3A-3ARSYNC-2C+and+File-3A-3ADSYNC] */
+ /* any read operation perform synchronously. used with SYNC or DSYNC. */
rb_define_const(rb_mFConst, "RSYNC", INT2FIX(O_RSYNC));
#endif
#ifdef O_NOFOLLOW
- /* {File::NOFOLLOW}[rdoc-ref:File::Constants@File-3A-3ANOFOLLOW] */
+ /* do not follow symlinks */
rb_define_const(rb_mFConst, "NOFOLLOW", INT2FIX(O_NOFOLLOW)); /* FreeBSD, Linux */
#endif
#ifdef O_NOATIME
- /* {File::NOATIME}[rdoc-ref:File::Constants@File-3A-3ANOATIME] */
+ /* do not change atime */
rb_define_const(rb_mFConst, "NOATIME", INT2FIX(O_NOATIME)); /* Linux */
#endif
#ifdef O_DIRECT
- /* {File::DIRECT}[rdoc-ref:File::Constants@File-3A-3ADIRECT] */
+ /* 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
- /* {File::TMPFILE}[rdoc-ref:File::Constants@File-3A-3ATMPFILE] */
+ /* Create an unnamed temporary file */
rb_define_const(rb_mFConst, "TMPFILE", INT2FIX(O_TMPFILE));
#endif
- /* {File::LOCK_SH}[rdoc-ref:File::Constants@File-3A-3ALOCK_SH] */
+ /* shared lock. see File#flock */
rb_define_const(rb_mFConst, "LOCK_SH", INT2FIX(LOCK_SH));
- /* {File::LOCK_EX}[rdoc-ref:File::Constants@File-3A-3ALOCK_EX] */
+ /* exclusive lock. see File#flock */
rb_define_const(rb_mFConst, "LOCK_EX", INT2FIX(LOCK_EX));
- /* {File::LOCK_UN}[rdoc-ref:File::Constants@File-3A-3ALOCK_UN] */
+ /* unlock. see File#flock */
rb_define_const(rb_mFConst, "LOCK_UN", INT2FIX(LOCK_UN));
- /* {File::LOCK_NB}[rdoc-ref:File::Constants@File-3A-3ALOCK_NB] */
+ /* non-blocking lock. used with LOCK_SH or LOCK_EX. see File#flock */
rb_define_const(rb_mFConst, "LOCK_NB", INT2FIX(LOCK_NB));
- /* {File::NULL}[rdoc-ref:File::Constants@File-3A-3ANULL] */
+ /* 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 0346812f42..54400e4f6b 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=%"PRIuSIZE", new_capacity=%"PRIuSIZE", malloc_offset=%"PRIuSIZE"", 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,9 +874,6 @@ typedef struct rb_objspace {
#if GC_DEBUG_STRESS_TO_CLASS
VALUE stress_to_class;
#endif
-
- rb_darray(VALUE *) weak_references;
- rb_postponed_job_handle_t finalize_deferred_pjob;
} rb_objspace_t;
@@ -975,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
@@ -1021,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;
@@ -1050,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];
};
/*
@@ -1098,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
@@ -1160,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
@@ -1280,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, m) ((objspace)->flags.mode = (unsigned int)gc_mode_verify(m))
+#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,22 +1209,25 @@ int ruby_gc_debug_indent = 0;
VALUE rb_mGC;
int ruby_disable_gc = 0;
int ruby_enable_autocompact = 0;
-#if RGENGC_CHECK_MODE
-gc_compact_compare_func ruby_autocompact_compare_func;
-#endif
-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);
@@ -1365,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,
@@ -1373,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 *);
@@ -1429,8 +1320,6 @@ PRINTF_ARGS(static void gc_report_body(int level, rb_objspace_t *objspace, const
static const char *obj_info(VALUE obj);
static const char *obj_type_name(VALUE obj);
-static void gc_finalize_deferred(void *dmy);
-
/*
* 1 - TSC (H/W Time Stamp Counter)
* 2 - getrusage
@@ -1472,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"
@@ -1606,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)
{
@@ -1647,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));
@@ -1782,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
@@ -1793,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++;
@@ -1821,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
@@ -1863,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--;
@@ -1876,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)
{
@@ -1912,10 +1865,6 @@ rb_objspace_alloc(void)
rb_objspace_t *objspace = calloc1(sizeof(rb_objspace_t));
objspace->flags.measure_gc = 1;
malloc_limit = gc_params.malloc_limit_min;
- objspace->finalize_deferred_pjob = rb_postponed_job_preregister(0, gc_finalize_deferred, objspace);
- if (objspace->finalize_deferred_pjob == POSTPONED_JOB_HANDLE_INVALID) {
- rb_bug("Could not preregister postponed job for GC");
- }
for (int i = 0; i < SIZE_POOL_COUNT; i++) {
rb_size_pool_t *size_pool = &size_pools[i];
@@ -1926,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;
@@ -1943,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;
@@ -1955,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);
@@ -1977,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);
}
@@ -2052,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 &&
@@ -2081,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)
{
@@ -2094,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)
@@ -2146,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) {
@@ -2166,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);
}
}
@@ -2382,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)
{
@@ -2396,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)
@@ -2427,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
@@ -2482,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
@@ -2497,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
@@ -2554,17 +2468,22 @@ 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 { \
@@ -2587,11 +2506,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
@@ -2608,7 +2522,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
@@ -2618,6 +2538,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++;
@@ -2640,6 +2563,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;
}
@@ -2686,6 +2627,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) {
@@ -2696,12 +2638,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
@@ -2771,6 +2718,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,8 +2727,7 @@ size_pool_idx_for_size(size_t size)
size_t size_pool_idx = 64 - nlz_int64(slot_count - 1);
if (size_pool_idx >= SIZE_POOL_COUNT) {
- rb_bug("size_pool_idx_for_size: allocation size too large "
- "(size=%"PRIuSIZE"u, size_pool_idx=%"PRIuSIZE"u)", size, size_pool_idx);
+ rb_bug("size_pool_idx_for_size: allocation size too large");
}
#if RGENGC_CHECK_MODE
@@ -2790,6 +2737,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
@@ -2814,13 +2765,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)
@@ -2839,17 +2792,9 @@ newobj_alloc(rb_objspace_t *objspace, rb_ractor_t *cr, size_t size_pool_idx, boo
}
}
- size_pool->total_allocated_objects++;
-
return obj;
}
-static void
-newobj_zero_slot(VALUE obj)
-{
- memset((char *)obj + sizeof(struct RBasic), 0, rb_gc_obj_slot_size(obj) - sizeof(struct RBasic));
-}
-
ALWAYS_INLINE(static VALUE newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_t *cr, int wb_protected, size_t size_pool_idx));
static inline VALUE
@@ -2875,9 +2820,12 @@ 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));
+ gc_event_hook_prep(objspace, RUBY_INTERNAL_EVENT_NEWOBJ, obj, newobj_fill(obj, 0, 0, 0));
}
RB_VM_LOCK_LEAVE_CR_LEV(cr, &lev);
@@ -2910,24 +2858,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 {
@@ -2942,7 +2891,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);
@@ -2952,14 +2908,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 */
@@ -2967,7 +2930,13 @@ 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
+rb_obj_embedded_size(uint32_t numiv)
+{
+ return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * numiv);
}
static VALUE
@@ -2977,15 +2946,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.
@@ -3009,7 +2983,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);
}
}
@@ -3049,7 +3023,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
@@ -3057,7 +3031,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
@@ -3116,7 +3090,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);
@@ -3136,7 +3110,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
@@ -3147,42 +3121,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;
}
@@ -3190,23 +3140,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 *
@@ -3330,8 +3271,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);
@@ -3469,53 +3408,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_P(obj) || !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,11 +3455,14 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
case T_OBJECT:
if (rb_shape_obj_too_complex(obj)) {
RB_DEBUG_COUNTER_INC(obj_obj_too_complex);
- st_free_table(ROBJECT_IV_HASH(obj));
+ rb_id_table_free(ROBJECT_IV_HASH(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);
@@ -3575,13 +3472,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));
}
@@ -3596,6 +3489,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;
@@ -3646,8 +3544,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) {
@@ -3656,11 +3568,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);
@@ -3675,6 +3622,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);
}
@@ -3707,6 +3655,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 !USE_RVARGC
+ xfree(RCLASS_EXT(obj));
+#endif
RB_DEBUG_COUNTER_INC(obj_iclass_ptr);
break;
@@ -3734,6 +3685,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);
@@ -3789,16 +3743,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);
- rb_vm_ci_free(ci);
- 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;
@@ -3870,14 +3816,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);
@@ -3896,7 +3841,6 @@ Init_gc_stress(void)
}
typedef int each_obj_callback(void *, void *, size_t, void *);
-typedef int each_page_callback(struct heap_page *, void *);
static void objspace_each_objects(rb_objspace_t *objspace, each_obj_callback *callback, void *data, bool protected);
static void objspace_reachable_objects_from_root(rb_objspace_t *, void (func)(const char *, VALUE, void *), void *);
@@ -3905,8 +3849,7 @@ struct each_obj_data {
rb_objspace_t *objspace;
bool reenable_incremental;
- each_obj_callback *each_obj_callback;
- each_page_callback *each_page_callback;
+ each_obj_callback *callback;
void *data;
struct heap_page **pages[SIZE_POOL_COUNT];
@@ -3926,7 +3869,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;
@@ -3980,15 +3927,9 @@ objspace_each_objects_try(VALUE arg)
uintptr_t pstart = (uintptr_t)page->start;
uintptr_t pend = pstart + (page->total_slots * size_pool->slot_size);
- if (!__asan_region_is_poisoned((void *)pstart, pend - pstart)) {
- if (data->each_obj_callback &&
- (*data->each_obj_callback)((void *)pstart, (void *)pend, size_pool->slot_size, data->data)) {
- break;
- }
- if (data->each_page_callback &&
- (*data->each_page_callback)(page, data->data)) {
- break;
- }
+ if (!__asan_region_is_poisoned((void *)pstart, pend - pstart) &&
+ (*data->callback)((void *)pstart, (void *)pend, size_pool->slot_size, data->data)) {
+ break;
}
page = ccan_list_next(&SIZE_POOL_EDEN_HEAP(size_pool)->pages, page, page_node);
@@ -4014,16 +3955,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
@@ -4043,10 +3982,9 @@ rb_objspace_each_objects(each_obj_callback *callback, void *data)
}
static void
-objspace_each_exec(bool protected, struct each_obj_data *each_obj_data)
+objspace_each_objects(rb_objspace_t *objspace, each_obj_callback *callback, void *data, bool protected)
{
/* Disable incremental GC */
- rb_objspace_t *objspace = each_obj_data->objspace;
bool reenable_incremental = FALSE;
if (protected) {
reenable_incremental = !objspace->flags.dont_incremental;
@@ -4055,35 +3993,18 @@ objspace_each_exec(bool protected, struct each_obj_data *each_obj_data)
objspace->flags.dont_incremental = TRUE;
}
- each_obj_data->reenable_incremental = reenable_incremental;
- memset(&each_obj_data->pages, 0, sizeof(each_obj_data->pages));
- memset(&each_obj_data->pages_counts, 0, sizeof(each_obj_data->pages_counts));
- rb_ensure(objspace_each_objects_try, (VALUE)each_obj_data,
- objspace_each_objects_ensure, (VALUE)each_obj_data);
-}
-
-static void
-objspace_each_objects(rb_objspace_t *objspace, each_obj_callback *callback, void *data, bool protected)
-{
struct each_obj_data each_obj_data = {
.objspace = objspace,
- .each_obj_callback = callback,
- .each_page_callback = NULL,
- .data = data,
- };
- objspace_each_exec(protected, &each_obj_data);
-}
+ .reenable_incremental = reenable_incremental,
-static void
-objspace_each_pages(rb_objspace_t *objspace, each_page_callback *callback, void *data, bool protected)
-{
- struct each_obj_data each_obj_data = {
- .objspace = objspace,
- .each_obj_callback = NULL,
- .each_page_callback = callback,
+ .callback = callback,
.data = data,
+
+ .pages = {NULL},
+ .pages_counts = {0},
};
- objspace_each_exec(protected, &each_obj_data);
+ rb_ensure(objspace_each_objects_try, (VALUE)&each_obj_data,
+ objspace_each_objects_ensure, (VALUE)&each_obj_data);
}
void
@@ -4259,45 +4180,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())
@@ -4378,7 +4260,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
@@ -4386,7 +4307,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
@@ -4430,20 +4351,16 @@ 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;
@@ -4503,7 +4420,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();
@@ -4542,44 +4459,9 @@ gc_finalize_deferred(void *dmy)
static void
gc_finalize_deferred_register(rb_objspace_t *objspace)
{
- /* will enqueue a call to gc_finalize_deferred */
- rb_postponed_job_trigger(objspace->finalize_deferred_pjob);
-}
-
-static int pop_mark_stack(mark_stack_t *stack, VALUE *data);
-
-static void
-gc_abort(rb_objspace_t *objspace)
-{
- if (is_incremental_marking(objspace)) {
- /* Remove all objects from the mark stack. */
- VALUE obj;
- while (pop_mark_stack(&objspace->mark_stack, &obj));
-
- objspace->flags.during_incremental_marking = FALSE;
+ if (rb_postponed_job_register_one(0, gc_finalize_deferred, objspace) == 0) {
+ rb_bug("gc_finalize_deferred_register: can't register finalizer.");
}
-
- if (is_lazy_sweeping(objspace)) {
- for (int i = 0; i < SIZE_POOL_COUNT; i++) {
- rb_size_pool_t *size_pool = &size_pools[i];
- rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
-
- heap->sweeping_page = NULL;
- struct heap_page *page = NULL;
-
- ccan_list_for_each(&heap->pages, page, page_node) {
- page->flags.before_sweep = false;
- }
- }
- }
-
- for (int i = 0; i < SIZE_POOL_COUNT; i++) {
- rb_size_pool_t *size_pool = &size_pools[i];
- rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
- rgengc_mark_and_rememberset_clear(objspace, heap);
- }
-
- gc_mode_set(objspace, gc_mode_none);
}
struct force_finalize_list {
@@ -4603,35 +4485,6 @@ force_chain_object(st_data_t key, st_data_t val, st_data_t arg)
bool rb_obj_is_main_ractor(VALUE gv);
void
-rb_objspace_free_objects(rb_objspace_t *objspace)
-{
- for (size_t i = 0; i < heap_allocated_pages; i++) {
- struct heap_page *page = heap_pages_sorted[i];
- short stride = page->slot_size;
-
- uintptr_t p = (uintptr_t)page->start;
- uintptr_t pend = p + page->total_slots * stride;
- for (; p < pend; p += stride) {
- VALUE vp = (VALUE)p;
- switch (BUILTIN_TYPE(vp)) {
- case T_DATA: {
- if (rb_obj_is_mutex(vp) || rb_obj_is_thread(vp) || rb_obj_is_main_ractor(vp)) {
- obj_free(objspace, vp);
- }
- break;
- }
- case T_ARRAY:
- obj_free(objspace, vp);
- break;
- default:
- break;
- }
- }
- }
-}
-
-
-void
rb_objspace_call_finalizer(rb_objspace_t *objspace)
{
size_t i;
@@ -4639,12 +4492,15 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace)
#if RGENGC_CHECK_MODE >= 2
gc_verify_internal_consistency(objspace);
#endif
+ gc_rest(objspace);
+
if (ATOMIC_EXCHANGE(finalizing, 1)) return;
/* run finalizers */
finalize_deferred(objspace);
GC_ASSERT(heap_pages_deferred_final == 0);
+ gc_rest(objspace);
/* prohibit incremental GC */
objspace->flags.dont_incremental = 1;
@@ -4662,9 +4518,6 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace)
}
}
- /* Abort incremental marking and lazy sweeping to speed up shutdown. */
- gc_abort(objspace);
-
/* prohibit GC because force T_DATA finalizers can break an object graph consistency */
dont_gc_on();
@@ -4689,20 +4542,23 @@ 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;
-
- obj_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:
- obj_free(objspace, vp);
- break;
- case T_SYMBOL:
- case T_ARRAY:
- case T_NONE:
+ if (RANY(p)->as.file.fptr) {
+ make_io_zombie(objspace, vp);
+ }
break;
default:
- if (rb_free_at_exit) {
- obj_free(objspace, vp);
- }
break;
}
if (poisoned) {
@@ -4722,7 +4578,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;
@@ -4733,7 +4589,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;
@@ -4764,7 +4620,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);
@@ -4775,7 +4631,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
@@ -4785,18 +4641,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;
@@ -4853,7 +4700,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)) {
@@ -4927,21 +4774,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_);
}
/*
@@ -5040,7 +4882,7 @@ obj_memsize_of(VALUE obj, int use_all_types)
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
if (rb_shape_obj_too_complex(obj)) {
- size += rb_st_memsize(ROBJECT_IV_HASH(obj));
+ size += rb_id_table_memsize(ROBJECT_IV_HASH(obj));
}
else if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) {
size += ROBJECT_IV_CAPACITY(obj) * sizeof(VALUE);
@@ -5048,22 +4890,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:
@@ -5072,7 +4919,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;
@@ -5083,10 +4930,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:
@@ -5098,10 +4950,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:
@@ -5320,7 +5173,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
@@ -5399,9 +5252,7 @@ try_move(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *free_page,
* full */
return false;
}
- asan_unlock_freelist(free_page);
free_page->freelist = RANY(dest)->as.free.next;
- asan_lock_freelist(free_page);
GC_ASSERT(RB_BUILTIN_TYPE(dest) == T_NONE);
@@ -5433,8 +5284,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)
@@ -5620,6 +5477,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++) {
@@ -5630,6 +5526,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++;
@@ -5675,7 +5578,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)) {
@@ -5698,7 +5601,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++;
@@ -5785,7 +5688,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();
@@ -5811,6 +5714,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)
{
@@ -5868,7 +5788,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;
@@ -5881,25 +5803,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++) {
@@ -5908,12 +5818,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;
@@ -5922,6 +5834,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)
{
@@ -5930,15 +5843,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;
@@ -5946,20 +5858,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. */
@@ -5977,6 +5897,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)
@@ -5995,9 +5916,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;
@@ -6011,15 +5934,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
@@ -6027,8 +5948,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;
@@ -6060,12 +5992,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);
@@ -6074,6 +6009,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;
@@ -6081,7 +6020,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);
@@ -6113,11 +6054,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) {
@@ -6129,13 +6072,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)
{
@@ -6208,7 +6151,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)
@@ -6245,8 +6187,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);
@@ -6274,7 +6214,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 */
@@ -6536,7 +6479,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);
@@ -6576,6 +6519,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)
{
@@ -6583,7 +6536,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]);
}
}
@@ -6593,7 +6546,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]);
}
}
@@ -6712,6 +6665,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);
}
@@ -6761,6 +6722,7 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
return;
case VM_METHOD_TYPE_REFINED:
gc_mark(objspace, (VALUE)def->body.refined.orig_me);
+ gc_mark(objspace, (VALUE)def->body.refined.owner);
break;
case VM_METHOD_TYPE_CFUNC:
case VM_METHOD_TYPE_ZSUPER:
@@ -6895,7 +6857,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);
}
@@ -6978,7 +6939,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++;
@@ -7001,8 +6962,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);
+ }
+ }
}
}
@@ -7017,9 +7001,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);
}
@@ -7083,14 +7069,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)) {
- GC_ASSERT(GET_HEAP_PAGE(obj)->pinned_slots <= GET_HEAP_PAGE(obj)->total_slots);
- GET_HEAP_PAGE(obj)->pinned_slots++;
- MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj);
- }
+ MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj);
}
}
}
@@ -7098,7 +7080,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);
}
@@ -7106,7 +7088,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);
}
@@ -7122,78 +7104,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.
*/
@@ -7227,7 +7137,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);
@@ -7260,7 +7170,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:
{
@@ -7274,34 +7184,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 and cc_type_refinement are not chained
- * from ccs so cc->cme should be marked; the cme might be
- * reachable only through cc in these cases.
- */
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
- if (vm_cc_super_p(cc) || vm_cc_refinement_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:
@@ -7317,14 +7208,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;
-}
-
-static void mark_cvc_tbl(rb_objspace_t *objspace, VALUE klass);
-
static void
gc_mark_children(rb_objspace_t *objspace, VALUE obj)
{
@@ -7364,29 +7247,18 @@ 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_no_pin(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:
@@ -7396,6 +7268,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));
@@ -7411,10 +7284,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;
@@ -7424,37 +7303,18 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
case T_STRING:
if (STR_SHARED_P(obj)) {
- if (STR_EMBED_P(any->as.string.as.heap.aux.shared)) {
- /* Embedded shared strings cannot be moved because this string
- * points into the slot of the shared string. There may be code
- * using the RSTRING_PTR on the stack, which would pin this
- * string but not pin the shared string, causing it to move. */
- gc_mark_and_pin(objspace, any->as.string.as.heap.aux.shared);
- }
- else {
- gc_mark(objspace, any->as.string.as.heap.aux.shared);
- }
+ gc_mark(objspace, any->as.string.as.heap.aux.shared);
}
break;
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)) {
- size_t *offset_list = (size_t *)RANY(obj)->as.typeddata.type->function.dmark;
-
- for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
- rb_gc_mark_movable(*(VALUE *)((char *)ptr + offset));
- }
- }
- 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;
@@ -7463,7 +7323,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
{
rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj));
if (rb_shape_obj_too_complex(obj)) {
- mark_tbl_no_pin(objspace, ROBJECT_IV_HASH(obj));
+ mark_m_tbl(objspace, ROBJECT_IV_HASH(obj));
}
else {
const VALUE * const ptr = ROBJECT_IVPTR(obj);
@@ -7472,12 +7332,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;
}
@@ -7528,6 +7393,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;
@@ -7553,8 +7423,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 */
@@ -7564,6 +7436,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");
@@ -7578,6 +7451,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);
@@ -8003,7 +7877,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++;
}
@@ -8111,7 +7985,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) : "");
}
@@ -8119,11 +7993,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;
@@ -8223,8 +8097,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);
}
@@ -8291,6 +8166,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)
{
@@ -8309,6 +8192,7 @@ heap_move_pooled_pages_to_free_pages(rb_heap_t *heap)
heap->pooled_pages = NULL;
}
}
+#endif
/* marks */
@@ -8320,6 +8204,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;
@@ -8327,6 +8212,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;
@@ -8342,14 +8228,6 @@ gc_marks_start(rb_objspace_t *objspace, int full_mark)
rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
rgengc_mark_and_rememberset_clear(objspace, heap);
heap_move_pooled_pages_to_free_pages(heap);
-
- if (objspace->flags.during_compacting) {
- struct heap_page *page = NULL;
-
- ccan_list_for_each(&heap->pages, page, page_node) {
- page->pinned_slots = 0;
- }
- }
}
}
else {
@@ -8369,6 +8247,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)
{
@@ -8412,36 +8291,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) {
@@ -8464,13 +8319,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");
@@ -8489,14 +8350,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) {
@@ -8523,15 +8379,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);
}
@@ -8552,11 +8416,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)
{
@@ -8587,10 +8466,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;
}
@@ -8646,7 +8521,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)) {
@@ -8787,9 +8662,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);
@@ -8799,62 +8676,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
@@ -8863,11 +8722,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 */
@@ -8905,10 +8760,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;
@@ -8927,7 +8790,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);
@@ -8936,7 +8799,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
@@ -8949,6 +8812,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
@@ -8983,20 +8861,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;
@@ -9033,9 +8911,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;
}
}
@@ -9053,8 +8930,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);
@@ -9062,11 +8940,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)
{
@@ -9092,7 +8984,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)) {
@@ -9100,6 +9003,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)
@@ -9149,7 +9055,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();
{
@@ -9180,7 +9086,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;
@@ -9199,6 +9105,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)
{
@@ -9207,7 +9156,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);
@@ -9263,7 +9212,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];
@@ -9316,23 +9267,10 @@ rb_gc_register_address(VALUE *addr)
rb_objspace_t *objspace = &rb_objspace;
struct gc_list *tmp;
- VALUE obj = *addr;
-
tmp = ALLOC(struct gc_list);
tmp->next = global_list;
tmp->varptr = addr;
global_list = tmp;
-
- /*
- * Because some C extensions have assignment-then-register bugs,
- * we guard `obj` here so that it would not get swept defensively.
- */
- 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);
- }
}
void
@@ -9498,10 +9436,21 @@ 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);
+ /* Explicitly enable compaction (GC.compact) */
+ if (do_full_mark && ruby_enable_autocompact) {
+ objspace->flags.during_compacting = TRUE;
+ }
+ else {
+ objspace->flags.during_compacting = !!(reason & GPR_FLAG_COMPACT);
+ }
+
if (!heap_allocated_pages) return FALSE; /* heap is not ready */
if (!(reason & GPR_FLAG_METHOD) && !ready_to_gc(objspace)) return TRUE; /* GC is not allowed */
@@ -9525,41 +9474,31 @@ gc_start(rb_objspace_t *objspace, unsigned int reason)
objspace->flags.immediate_sweep = !(flag & (1<<gc_stress_no_immediate_sweep));
}
+ else {
+ if (objspace->rgengc.need_major_gc) {
+ reason |= objspace->rgengc.need_major_gc;
+ do_full_mark = TRUE;
+ }
+ else if (RGENGC_FORCE_MAJOR_GC) {
+ reason = GPR_FLAG_MAJOR_BY_FORCE;
+ do_full_mark = TRUE;
+ }
- if (objspace->rgengc.need_major_gc) {
- reason |= objspace->rgengc.need_major_gc;
- do_full_mark = TRUE;
- }
- else if (RGENGC_FORCE_MAJOR_GC) {
- reason = GPR_FLAG_MAJOR_BY_FORCE;
- do_full_mark = TRUE;
+ objspace->rgengc.need_major_gc = GPR_FLAG_NONE;
}
- objspace->rgengc.need_major_gc = GPR_FLAG_NONE;
-
if (do_full_mark && (reason & GPR_FLAG_MAJOR_MASK) == 0) {
reason |= GPR_FLAG_MAJOR_BY_FORCE; /* GC by CAPI, METHOD, and so on. */
}
- if (objspace->flags.dont_incremental ||
- reason & GPR_FLAG_IMMEDIATE_MARK ||
- ruby_gc_stressful) {
+#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;
}
-
- /* Explicitly enable compaction (GC.compact) */
- if (do_full_mark && ruby_enable_autocompact) {
- objspace->flags.during_compacting = TRUE;
-#if RGENGC_CHECK_MODE
- objspace->rcompactor.compare_func = ruby_autocompact_compare_func;
#endif
- }
- else {
- objspace->flags.during_compacting = !!(reason & GPR_FLAG_COMPACT);
- }
if (!GC_ENABLE_LAZY_SWEEP || objspace->flags.dont_incremental) {
objspace->flags.immediate_sweep = TRUE;
@@ -9594,21 +9533,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);
@@ -9629,19 +9565,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);
}
}
@@ -9658,7 +9586,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';
@@ -9730,7 +9660,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";
@@ -9743,37 +9674,71 @@ 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;
}
}
+#ifndef MEASURE_GC
+#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
@@ -9781,12 +9746,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;
@@ -9810,57 +9777,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);
-}
-#ifndef MEASURE_GC
-#define MEASURE_GC (objspace->flags.measure_gc)
-#endif
-
-static void
-gc_marking_enter(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- if (MEASURE_GC) {
- gc_clock_start(&objspace->profile.marking_start_time);
- }
-}
-
-static void
-gc_marking_exit(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- if (MEASURE_GC) {
- 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);
-
- if (MEASURE_GC) {
- gc_clock_start(&objspace->profile.sweeping_start_time);
- }
-}
-
-static void
-gc_sweeping_exit(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- if (MEASURE_GC) {
- 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 *
@@ -9892,31 +9824,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)
{
@@ -9944,61 +9851,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)
{
@@ -10039,9 +9891,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));
@@ -10056,13 +9908,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;
@@ -10071,28 +9934,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;
@@ -10102,12 +9962,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 */
@@ -10121,14 +9981,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) {
@@ -10152,7 +10011,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;
@@ -10164,18 +10022,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;
@@ -10188,7 +10034,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];
@@ -10208,7 +10054,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);
@@ -10229,10 +10075,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) {
@@ -10240,26 +10089,29 @@ 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
}
}
-static void gc_ref_update_table_values_only(rb_objspace_t *objspace, st_table *tbl);
+static void update_m_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl);
static void
gc_ref_update_object(rb_objspace_t *objspace, VALUE v)
@@ -10267,19 +10119,26 @@ gc_ref_update_object(rb_objspace_t *objspace, VALUE v)
VALUE *ptr = ROBJECT_IVPTR(v);
if (rb_shape_obj_too_complex(v)) {
- gc_ref_update_table_values_only(objspace, ROBJECT_IV_HASH(v));
+ update_m_tbl(objspace, ROBJECT_IV_HASH(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]);
@@ -10345,7 +10204,7 @@ hash_foreach_replace_value(st_data_t key, st_data_t value, st_data_t argp, int e
}
static void
-gc_ref_update_table_values_only(rb_objspace_t *objspace, st_table *tbl)
+gc_update_tbl_refs(rb_objspace_t * objspace, st_table *tbl)
{
if (!tbl || tbl->num_entries == 0) return;
@@ -10354,12 +10213,6 @@ gc_ref_update_table_values_only(rb_objspace_t *objspace, st_table *tbl)
}
}
-void
-rb_gc_ref_update_table_values_only(st_table *tbl)
-{
- gc_ref_update_table_values_only(&rb_objspace, tbl);
-}
-
static void
gc_update_table_refs(rb_objspace_t * objspace, st_table *tbl)
{
@@ -10370,7 +10223,7 @@ gc_update_table_refs(rb_objspace_t * objspace, st_table *tbl)
}
}
-/* Update MOVED references in a VALUE=>VALUE st_table */
+/* Update MOVED references in an st_table */
void
rb_gc_update_tbl_refs(st_table *ptr)
{
@@ -10412,6 +10265,7 @@ gc_ref_update_method_entry(rb_objspace_t *objspace, rb_method_entry_t *me)
return;
case VM_METHOD_TYPE_REFINED:
TYPED_UPDATE_IF_MOVED(objspace, struct rb_method_entry_struct *, def->body.refined.orig_me);
+ UPDATE_IF_MOVED(objspace, def->body.refined.owner);
break;
case VM_METHOD_TYPE_CFUNC:
case VM_METHOD_TYPE_ZSUPER:
@@ -10434,20 +10288,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)
{
@@ -10487,7 +10327,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);
@@ -10495,18 +10335,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;
}
}
}
@@ -10628,14 +10467,9 @@ static enum rb_id_table_iterator_result
update_cvc_tbl_i(VALUE cvc_entry, void *data)
{
struct rb_cvar_class_tbl_entry *entry;
- rb_objspace_t * objspace = (rb_objspace_t *)data;
entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
- if (entry->cref) {
- TYPED_UPDATE_IF_MOVED(objspace, rb_cref_t *, entry->cref);
- }
-
entry->class_value = rb_gc_location(entry->class_value);
return ID_TABLE_CONTINUE;
@@ -10651,29 +10485,6 @@ 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);
-
- return ID_TABLE_CONTINUE;
-}
-
-static void
-mark_cvc_tbl(rb_objspace_t *objspace, VALUE klass)
-{
- struct rb_id_table *tbl = RCLASS_CVC_TBL(klass);
- if (tbl) {
- rb_id_table_foreach_values(tbl, mark_cvc_tbl_i, objspace);
- }
-}
-
-static enum rb_id_table_iterator_result
update_const_table(VALUE value, void *data)
{
rb_const_entry_t *ce = (rb_const_entry_t *)value;
@@ -10732,47 +10543,35 @@ 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_ref_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);
update_superclasses(objspace, obj);
- if (rb_shape_obj_too_complex(obj)) {
- gc_ref_update_table_values_only(objspace, RCLASS_IV_HASH(obj));
- }
- else {
- for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
- UPDATE_IF_MOVED(objspace, RCLASS_IVPTR(obj)[i]);
- }
+ for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
+ UPDATE_IF_MOVED(objspace, RCLASS_IVPTR(obj)[i]);
}
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:
- if (RICLASS_OWNS_M_TBL_P(obj)) {
+ if (FL_TEST(obj, RICLASS_IS_ORIGIN) &&
+ !FL_TEST(obj, RICLASS_ORIGIN_SHARED_MTBL)) {
update_m_tbl(objspace, RCLASS_M_TBL(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);
@@ -10801,10 +10600,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)) {
@@ -10812,24 +10622,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)) {
- size_t *offset_list = (size_t *)RANY(obj)->as.typeddata.type->function.dmark;
-
- for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
- VALUE *ref = (VALUE *)((char *)ptr + offset);
- if (SPECIAL_CONST_P(*ref)) continue;
- *ref = rb_gc_location(*ref);
- }
- }
- 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);
}
@@ -10916,7 +10718,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 */
@@ -10930,9 +10732,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) {
@@ -10959,8 +10761,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);
@@ -10985,15 +10785,14 @@ 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);
- gc_ref_update_table_values_only(objspace, objspace->obj_to_id_tbl);
+ gc_update_tbl_refs(objspace, objspace->obj_to_id_tbl);
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
@@ -11054,7 +10853,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)));
}
}
@@ -11063,7 +10862,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)));
}
}
@@ -11128,39 +10927,6 @@ gc_compact(VALUE self)
#endif
#if GC_CAN_COMPILE_COMPACTION
-
-struct desired_compaction_pages_i_data {
- rb_objspace_t *objspace;
- size_t required_slots[SIZE_POOL_COUNT];
-};
-
-static int
-desired_compaction_pages_i(struct heap_page *page, void *data)
-{
- struct desired_compaction_pages_i_data *tdata = data;
- rb_objspace_t *objspace = tdata->objspace;
- VALUE vstart = (VALUE)page->start;
- VALUE vend = vstart + (VALUE)(page->total_slots * page->size_pool->slot_size);
-
-
- for (VALUE v = vstart; v != vend; v += page->size_pool->slot_size) {
- /* skip T_NONEs; they won't be moved */
- void *poisoned = asan_unpoison_object_temporary(v);
- if (BUILTIN_TYPE(v) == T_NONE) {
- if (poisoned) {
- asan_poison_object(v);
- }
- continue;
- }
-
- rb_size_pool_t *dest_pool = gc_compact_destination_pool(objspace, page->size_pool, v);
- size_t dest_pool_idx = dest_pool - size_pools;
- tdata->required_slots[dest_pool_idx]++;
- }
-
- return 0;
-}
-
static VALUE
gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE double_heap, VALUE expand_heap, VALUE toward_empty)
{
@@ -11168,6 +10934,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");
@@ -11178,59 +10945,23 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do
gc_rest(objspace);
/* if both double_heap and expand_heap are set, expand_heap takes precedence */
- if (RTEST(expand_heap)) {
- struct desired_compaction_pages_i_data desired_compaction = {
- .objspace = objspace,
- .required_slots = {0},
- };
- /* Work out how many objects want to be in each size pool, taking account of moves */
- objspace_each_pages(objspace, desired_compaction_pages_i, &desired_compaction, TRUE);
-
- /* Find out which pool has the most pages */
- size_t max_existing_pages = 0;
- for(int i = 0; i < SIZE_POOL_COUNT; i++) {
- rb_size_pool_t *size_pool = &size_pools[i];
- rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
- max_existing_pages = MAX(max_existing_pages, heap->total_pages);
- }
- /* Add pages to each size pool so that compaction is guaranteed to move every object */
+ if (RTEST(double_heap) || RTEST(expand_heap)) {
for (int i = 0; i < SIZE_POOL_COUNT; i++) {
rb_size_pool_t *size_pool = &size_pools[i];
rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
- size_t pages_to_add = 0;
- /*
- * Step 1: Make sure every pool has the same number of pages, by adding empty pages
- * to smaller pools. This is required to make sure the compact cursor can advance
- * through all of the pools in `gc_sweep_compact` without hitting the "sweep &
- * compact cursors met" condition on some pools before fully compacting others
- */
- pages_to_add += max_existing_pages - heap->total_pages;
- /*
- * Step 2: Now add additional free pages to each size pool sufficient to hold all objects
- * that want to be in that size pool, whether moved into it or moved within it
- */
- pages_to_add += slots_to_pages_for_size_pool(objspace, size_pool, desired_compaction.required_slots[i]);
- /*
- * Step 3: Add two more pages so that the compact & sweep cursors will meet _after_ all objects
- * have been moved, and not on the last iteration of the `gc_sweep_compact` loop
- */
- pages_to_add += 2;
-
- heap_add_pages(objspace, size_pool, heap, pages_to_add);
- }
- }
- else if (RTEST(double_heap)) {
- for (int i = 0; i < SIZE_POOL_COUNT; i++) {
- rb_size_pool_t *size_pool = &size_pools[i];
- rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
- heap_add_pages(objspace, size_pool, heap, heap->total_pages);
+ if (RTEST(expand_heap)) {
+ 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);
+ }
}
-
}
if (RTEST(toward_empty)) {
- objspace->rcompactor.compare_func = compare_free_slots;
+ gc_sort_heap_by_empty_slots(objspace);
}
}
RB_VM_LOCK_LEAVE();
@@ -11240,7 +10971,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
@@ -11257,7 +10987,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);
}
@@ -11265,7 +10995,7 @@ rb_gc(void)
int
rb_during_gc(void)
{
- unless_objspace(objspace) { return FALSE; }
+ rb_objspace_t *objspace = &rb_objspace;
return during_gc;
}
@@ -11308,7 +11038,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;
@@ -11348,9 +11077,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
}
@@ -11401,9 +11127,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 */
@@ -11438,8 +11161,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,
@@ -11469,7 +11190,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,
@@ -11490,8 +11210,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);
@@ -11521,7 +11239,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);
@@ -11534,12 +11251,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)
{
@@ -11565,9 +11276,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);
@@ -11582,8 +11291,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);
@@ -11673,9 +11382,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
};
@@ -11695,9 +11401,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
}
}
@@ -11741,9 +11444,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 */
@@ -11898,18 +11598,6 @@ gc_set_auto_compact(VALUE _, VALUE v)
GC_ASSERT(GC_COMPACTION_SUPPORTED);
ruby_enable_autocompact = RTEST(v);
-
-#if RGENGC_CHECK_MODE
- ruby_autocompact_compare_func = NULL;
-
- if (SYMBOL_P(v)) {
- ID id = RB_SYM2ID(v);
- if (id == rb_intern("empty")) {
- ruby_autocompact_compare_func = compare_free_slots;
- }
- }
-#endif
-
return v;
}
#else
@@ -12039,20 +11727,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;
}
@@ -12063,6 +11745,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.
@@ -12109,7 +11793,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);
@@ -12120,7 +11807,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;
@@ -12156,7 +11842,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,
@@ -12532,7 +12218,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 *
@@ -12593,23 +12279,18 @@ objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
} \
} while (0)
-static void
-check_malloc_not_in_gc(rb_objspace_t *objspace, const char *msg)
-{
- if (UNLIKELY(malloc_during_gc_p(objspace))) {
- dont_gc_on();
- during_gc = false;
- rb_bug("Cannot %s during GC", msg);
- }
-}
-
/* these shouldn't be called directly.
* objspace_* functions do not check allocation size.
*/
static void *
objspace_xmalloc0(rb_objspace_t *objspace, size_t size)
{
- check_malloc_not_in_gc(objspace, "malloc");
+ if (UNLIKELY(malloc_during_gc_p(objspace))) {
+ rb_warn("malloc during GC detected, this could cause crashes if it triggers another GC");
+#if RGENGC_CHECK_MODE || RUBY_DEBUG
+ rb_bug("Cannot malloc during GC");
+#endif
+ }
void *mem;
@@ -12628,7 +12309,12 @@ xmalloc2_size(const size_t count, const size_t elsize)
static void *
objspace_xrealloc(rb_objspace_t *objspace, void *ptr, size_t new_size, size_t old_size)
{
- check_malloc_not_in_gc(objspace, "realloc");
+ if (UNLIKELY(malloc_during_gc_p(objspace))) {
+ rb_warn("realloc during GC detected, this could cause crashes if it triggers another GC");
+#if RGENGC_CHECK_MODE || RUBY_DEBUG
+ rb_bug("Cannot realloc during GC");
+#endif
+ }
void *mem;
@@ -12928,16 +12614,8 @@ ruby_xrealloc2_body(void *ptr, size_t n, size_t size)
void
ruby_sized_xfree(void *x, size_t size)
{
- if (LIKELY(x)) {
- /* It's possible for a C extension's pthread destructor function set by pthread_key_create
- * to be called after ruby_vm_destruct and attempt to free memory. Fall back to mimfree in
- * that case. */
- if (LIKELY(GET_VM())) {
- objspace_xfree(&rb_objspace, x, size);
- }
- else {
- ruby_mimfree(x);
- }
+ if (x) {
+ objspace_xfree(&rb_objspace, x, size);
}
}
@@ -13099,8 +12777,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);
}
@@ -13110,6 +12787,481 @@ 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 void
+wmap_compact(void *ptr)
+{
+ struct weakmap *w = ptr;
+ if (w->wmap2obj) rb_gc_update_tbl_refs(w->wmap2obj);
+ if (w->obj2wmap) rb_gc_update_tbl_refs(w->obj2wmap);
+ 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_final_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
+{
+ VALUE wmap, *ptr, size, i, j;
+ if (!existing) return ST_STOP;
+ wmap = (VALUE)arg, ptr = (VALUE *)*value;
+ for (i = j = 1, size = ptr[0]; i <= size; ++i) {
+ if (ptr[i] != wmap) {
+ ptr[j++] = ptr[i];
+ }
+ }
+ if (j == 1) {
+ ruby_sized_xfree(ptr, i * sizeof(VALUE));
+ return ST_DELETE;
+ }
+ if (j < i) {
+ SIZED_REALLOC_N(ptr, VALUE, j + 1, i);
+ ptr[0] = j;
+ *value = (st_data_t)ptr;
+ }
+ 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_final_func, 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];
+ ++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;
+}
+
+/* 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);
+ }
+
+ st_update(w->obj2wmap, (st_data_t)value, wmap_aset_update, key);
+ st_insert(w->wmap2obj, (st_data_t)key, (st_data_t)value);
+ 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 ------------------------------
*/
@@ -13338,7 +13490,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
@@ -13370,7 +13522,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;
}
@@ -13440,7 +13594,7 @@ gc_profile_record_get(VALUE _)
gc_profile_record *record = &objspace->profile.records[i];
prof = rb_hash_new();
- rb_hash_aset(prof, ID2SYM(rb_intern("GC_FLAGS")), gc_info_decode(objspace, rb_hash_new(), record->flags));
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_FLAGS")), gc_info_decode(0, rb_hash_new(), record->flags));
rb_hash_aset(prof, ID2SYM(rb_intern("GC_TIME")), DBL2NUM(record->gc_time));
rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DBL2NUM(record->gc_invoke_time));
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), SIZET2NUM(record->heap_use_size));
@@ -13834,7 +13988,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 ",
@@ -13898,12 +14052,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: {
@@ -13934,8 +14089,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;
}
@@ -13947,7 +14103,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;
}
@@ -13961,20 +14117,14 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
}
case T_OBJECT:
{
- if (rb_shape_obj_too_complex(obj)) {
- size_t hash_len = rb_st_table_size(ROBJECT_IV_HASH(obj));
- APPEND_F("(too_complex) len:%"PRIuSIZE"", hash_len);
+ uint32_t len = ROBJECT_IV_CAPACITY(obj);
+
+ if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) {
+ APPEND_F("(embed) len:%d", len);
}
else {
- uint32_t len = ROBJECT_IV_CAPACITY(obj);
-
- if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) {
- APPEND_F("(embed) len:%d", len);
- }
- else {
- VALUE *ptr = ROBJECT_IVPTR(obj);
- APPEND_F("len:%d ptr:%p", len, (void *)ptr);
- }
+ VALUE *ptr = ROBJECT_IVPTR(obj);
+ APPEND_F("len:%d ptr:%p", len, (void *)ptr);
}
}
break;
@@ -14009,7 +14159,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
{
const rb_method_entry_t *me = &RANY(obj)->as.imemo.ment;
- APPEND_F(":%s (%s%s%s%s) type:%s aliased:%d owner:%p defined_class:%p",
+ APPEND_F(":%s (%s%s%s%s) type:%s alias:%d owner:%p defined_class:%p",
rb_id2name(me->called_id),
METHOD_ENTRY_VISI(me) == METHOD_VISI_PUBLIC ? "pub" :
METHOD_ENTRY_VISI(me) == METHOD_VISI_PRIVATE ? "pri" : "pro",
@@ -14017,7 +14167,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
METHOD_ENTRY_CACHED(me) ? ",cc" : "",
METHOD_ENTRY_INVALIDATED(me) ? ",inv" : "",
me->def ? rb_method_type_name(me->def->type) : "NULL",
- me->def ? me->def->aliased : -1,
+ me->def ? me->def->alias_count : -1,
(void *)me->owner, // obj_info(me->owner),
(void *)me->defined_class); //obj_info(me->defined_class)));
@@ -14131,7 +14281,7 @@ obj_info(VALUE obj)
}
#endif
-const char *
+MJIT_FUNC_EXPORTED const char *
rb_obj_info(VALUE obj)
{
return obj_info(obj);
@@ -14144,7 +14294,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];
@@ -14176,14 +14326,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");
@@ -14205,6 +14355,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[, ...])
@@ -14218,7 +14369,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;
@@ -14243,11 +14394,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
@@ -14277,6 +14429,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,
@@ -14296,13 +14458,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;
@@ -14319,12 +14495,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");
@@ -14353,13 +14525,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);
@@ -14375,10 +14570,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..b2356444c6
--- /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);
+
+VALUE rb_gc_disable_no_rest(void);
+
+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);
+
+RUBY_SYMBOL_EXPORT_END
+
+#endif /* RUBY_GC_H */
diff --git a/gc.rb b/gc.rb
index c9c985b994..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,36 +10,30 @@
# 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
- # Alias of GC.start
def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end
@@ -124,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]
@@ -155,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]
@@ -170,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.
@@ -197,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.
@@ -219,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
@@ -317,13 +282,12 @@ 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
module ObjectSpace
- # Alias of GC.start
def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
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 40d79c6a3c..6dac400cb8 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.16.3 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.3.9 https://github.com/ruby/rexml
-rss 0.3.1 https://github.com/ruby/rss
-net-ftp 0.3.4 https://github.com/ruby/net-ftp
-net-imap 0.4.19 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.2.5 https://github.com/ruby/rexml
+rss 0.2.9 https://github.com/ruby/rss
+net-ftp 0.2.0 https://github.com/ruby/net-ftp
+net-imap 0.3.4 https://github.com/ruby/net-imap
net-pop 0.1.2 https://github.com/ruby/net-pop
-net-smtp 0.5.1 https://github.com/ruby/net-smtp
+net-smtp 0.3.3 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.4.0 https://github.com/ruby/rbs
-typeprof 0.21.9 https://github.com/ruby/typeprof
-debug 1.9.2 https://github.com/ruby/debug
-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/core_assertions.rb b/gems/lib/core_assertions.rb
deleted file mode 100644
index 7334063885..0000000000
--- a/gems/lib/core_assertions.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative "../../tool/lib/core_assertions.rb"
diff --git a/gems/lib/rake/extensiontask.rb b/gems/lib/rake/extensiontask.rb
deleted file mode 100644
index aa668935fc..0000000000
--- a/gems/lib/rake/extensiontask.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-module Rake
- class ExtensionTask < TaskLib
- def initialize(...)
- task :compile do |args|
- puts "Dummy `compile` task defined in #{__FILE__}"
- puts "#{args.name} => #{args.prereqs.join(' ')}"
- end
- end
- end
-end
diff --git a/hash.c b/hash.c
index 6b1941ebcb..5204d8b018 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;
@@ -237,7 +221,7 @@ obj_any_hash(VALUE obj)
return FIX2LONG(hval);
}
-st_index_t
+static st_index_t
rb_any_hash(VALUE a)
{
return any_hash(a, obj_any_hash);
@@ -377,17 +361,16 @@ 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
@@ -395,6 +378,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)
{
@@ -410,13 +409,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
@@ -464,20 +463,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__)
@@ -487,10 +480,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;
@@ -504,6 +497,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);
@@ -541,6 +535,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;
}
@@ -549,30 +550,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)
+{
+ HASH_ASSERT(RHASH_AR_TABLE_P(hash));
+ return RHASH(hash)->as.ar;
+}
+
+st_table *
+rb_hash_st_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.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)
{
@@ -627,7 +667,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));
@@ -642,7 +702,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 */
@@ -689,83 +749,92 @@ 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);
}
-void rb_st_add_direct_with_hash(st_table *tab, st_data_t key, st_data_t value, st_hash_t hash); // st.c
+static void
+ar_try_convert_table(VALUE hash)
+{
+ if (!RHASH_AR_TABLE_P(hash)) return;
-enum ar_each_key_type {
- ar_each_key_copy,
- ar_each_key_cmp,
- ar_each_key_insert,
-};
+ const unsigned size = RHASH_AR_TABLE_SIZE(hash);
-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 *new_tab;
+ st_index_t i;
+
+ if (size < RHASH_AR_TABLE_MAX_SIZE) {
+ return;
}
- return 0;
+ new_tab = st_init_table_with_size(&objhash, size * 2);
+
+ for (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);
+ }
+ ar_free_and_clear_table(hash);
+ RHASH_ST_TABLE_SET(hash, new_tab);
+ return;
}
static st_table *
ar_force_convert_table(VALUE hash, const char *file, int line)
{
+ st_table *new_tab;
+
if (RHASH_ST_TABLE_P(hash)) {
return RHASH_ST_TABLE(hash);
}
+
+ if (RHASH_AR_TABLE(hash)) {
+ unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
+
+#if defined(RHASH_CONVERT_TABLE_DEBUG) && RHASH_CONVERT_TABLE_DEBUG
+ rb_obj_info_dump(hash);
+ fprintf(stderr, "force_convert: %s:%d\n", file, line);
+ RB_DEBUG_COUNTER_INC(obj_hash_force_convert);
+#endif
+
+ new_tab = st_init_table_with_size(&objhash, RHASH_AR_TABLE_SIZE(hash));
+
+ for (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(new_tab, pair->key, pair->val);
+ }
+ ar_free_and_clear_table(hash);
+ }
else {
- ar_table *ar = RHASH_AR_TABLE(hash);
- st_hash_t hashes[RHASH_AR_TABLE_MAX_SIZE];
- unsigned int bound, size;
-
- // 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 (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]);
- }
+ new_tab = st_init_table(&objhash);
+ }
+ RHASH_ST_TABLE_SET(hash, new_tab);
- // 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);
-
- // make st
- st_table tab;
- st_table *new_tab = &tab;
- rb_st_init_existing_table_with_size(new_tab, &objhash, size);
- ar_each_key(ar, bound, ar_each_key_insert, NULL, new_tab, hashes);
- hash_ar_free_and_clear_table(hash);
- RHASH_ST_TABLE_SET(hash, new_tab);
- return RHASH_ST_TABLE(hash);
+ 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
@@ -818,6 +887,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);
@@ -828,14 +898,6 @@ ar_add_direct_with_hash(VALUE hash, st_data_t key, st_data_t val, st_hash_t hash
}
}
-static void
-ensure_ar_table(VALUE hash)
-{
- if (!RHASH_AR_TABLE_P(hash)) {
- rb_raise(rb_eRuntimeError, "hash representation was changed during iteration");
- }
-}
-
static int
ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg)
{
@@ -847,7 +909,6 @@ ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_c
ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
enum st_retval retval = (*func)(pair->key, pair->val, arg, 0);
- ensure_ar_table(hash);
/* pair may be not valid here because of theap */
switch (retval) {
@@ -922,7 +983,6 @@ ar_foreach_check(VALUE hash, st_foreach_check_callback_func *func, st_data_t arg
hint = ar_hint(hash, i);
retval = (*func)(key, pair->val, arg, 0);
- ensure_ar_table(hash);
hash_verify(hash);
switch (retval) {
@@ -972,6 +1032,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;
}
@@ -983,7 +1044,6 @@ ar_update(VALUE hash, st_data_t key,
old_key = key;
retval = (*func)(&key, &value, arg, existing);
/* pair can be invalid here because of theap */
- ensure_ar_table(hash);
switch (retval) {
case ST_CONTINUE:
@@ -1021,6 +1081,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) {
@@ -1028,6 +1090,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);
@@ -1162,16 +1225,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
@@ -1187,32 +1278,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);
-
- xfree(tab->bins);
- xfree(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);
@@ -1302,79 +1393,72 @@ hash_foreach_iter(st_data_t key, st_data_t value, st_data_t argp, int error)
return hash_iter_status_check(status);
}
-static unsigned long
+static int
iter_lev_in_ivar(VALUE hash)
{
VALUE levval = rb_ivar_get(hash, id_hash_iter_lev);
HASH_ASSERT(FIXNUM_P(levval));
- long lev = FIX2LONG(levval);
- HASH_ASSERT(lev >= 0);
- return (unsigned long)lev;
+ return FIX2INT(levval);
}
void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
static void
-iter_lev_in_ivar_set(VALUE hash, unsigned long lev)
+iter_lev_in_ivar_set(VALUE hash, int lev)
{
- HASH_ASSERT(lev >= RHASH_LEV_MAX);
- HASH_ASSERT(POSFIXABLE(lev)); /* POSFIXABLE means fitting to long */
- rb_ivar_set_internal(hash, id_hash_iter_lev, LONG2FIX((long)lev));
+ rb_ivar_set_internal(hash, id_hash_iter_lev, INT2FIX(lev));
}
-static inline unsigned long
+static int
iter_lev_in_flags(VALUE hash)
{
- return (unsigned long)((RBASIC(hash)->flags >> RHASH_LEV_SHIFT) & RHASH_LEV_MAX);
+ unsigned int u = (unsigned int)((RBASIC(hash)->flags >> RHASH_LEV_SHIFT) & RHASH_LEV_MAX);
+ return (int)u;
}
-static inline void
-iter_lev_in_flags_set(VALUE hash, unsigned long lev)
+static int
+RHASH_ITER_LEV(VALUE hash)
{
- HASH_ASSERT(lev <= RHASH_LEV_MAX);
- RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((VALUE)lev << RHASH_LEV_SHIFT));
-}
+ int lev = iter_lev_in_flags(hash);
-static inline bool
-hash_iterating_p(VALUE hash)
-{
- return iter_lev_in_flags(hash) > 0;
+ if (lev == RHASH_LEV_MAX) {
+ return iter_lev_in_ivar(hash);
+ }
+ else {
+ return lev;
+ }
}
static void
hash_iter_lev_inc(VALUE hash)
{
- unsigned long lev = iter_lev_in_flags(hash);
+ int lev = iter_lev_in_flags(hash);
if (lev == RHASH_LEV_MAX) {
- lev = iter_lev_in_ivar(hash) + 1;
- if (!POSFIXABLE(lev)) { /* paranoiac check */
- rb_raise(rb_eRuntimeError, "too much nested iterations");
- }
+ lev = iter_lev_in_ivar(hash);
+ iter_lev_in_ivar_set(hash, lev+1);
}
else {
lev += 1;
- iter_lev_in_flags_set(hash, lev);
- if (lev < RHASH_LEV_MAX) return;
+ RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((VALUE)lev << RHASH_LEV_SHIFT));
+ if (lev == RHASH_LEV_MAX) {
+ iter_lev_in_ivar_set(hash, lev);
+ }
}
- iter_lev_in_ivar_set(hash, lev);
}
static void
hash_iter_lev_dec(VALUE hash)
{
- unsigned long lev = iter_lev_in_flags(hash);
+ int lev = iter_lev_in_flags(hash);
if (lev == RHASH_LEV_MAX) {
lev = iter_lev_in_ivar(hash);
- if (lev > RHASH_LEV_MAX) {
- iter_lev_in_ivar_set(hash, lev-1);
- return;
- }
- rb_attr_delete(hash, id_hash_iter_lev);
+ HASH_ASSERT(lev > 0);
+ iter_lev_in_ivar_set(hash, lev-1);
}
- else if (lev == 0) {
- rb_raise(rb_eRuntimeError, "iteration level underflow");
+ else {
+ HASH_ASSERT(lev > 0);
+ RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((lev-1) << RHASH_LEV_SHIFT));
}
- iter_lev_in_flags_set(hash, lev - 1);
}
static VALUE
@@ -1452,23 +1536,11 @@ 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 (!hash_iterating_p(hash) && 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);
@@ -1478,8 +1550,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
@@ -1505,16 +1576,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;
}
@@ -1527,32 +1601,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;
}
@@ -1560,21 +1613,13 @@ hash_copy(VALUE ret, VALUE hash)
static VALUE
hash_dup_with_compare_by_id(VALUE hash)
{
- VALUE dup = hash_alloc_flags(rb_cHash, 0, Qnil, RHASH_ST_TABLE_P(hash));
- if (RHASH_ST_TABLE_P(hash)) {
- RHASH_SET_ST_FLAG(dup);
- }
- else {
- RHASH_UNSET_ST_FLAG(dup);
- }
-
- return hash_copy(dup, hash);
+ return hash_copy(copy_compare_by_id(rb_hash_new(), hash), 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);
}
@@ -1589,7 +1634,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);
@@ -1602,7 +1647,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);
@@ -1663,7 +1708,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_force_convert_table(hash, __FILE__, __LINE__);
+ ar_try_convert_table(hash);
}
else {
return result;
@@ -1720,14 +1765,14 @@ tbl_update(VALUE hash, VALUE key, tbl_update_func func, st_data_t optional_arg)
return ret;
}
-#define UPDATE_CALLBACK(iter_p, func) ((iter_p) ? func##_noinsert : func##_insert)
+#define UPDATE_CALLBACK(iter_lev, func) ((iter_lev) > 0 ? func##_noinsert : func##_insert)
-#define RHASH_UPDATE_ITER(h, iter_p, key, func, a) do { \
- tbl_update((h), (key), UPDATE_CALLBACK(iter_p, func), (st_data_t)(a)); \
+#define RHASH_UPDATE_ITER(h, iter_lev, key, func, a) do { \
+ tbl_update((h), (key), UPDATE_CALLBACK((iter_lev), func), (st_data_t)(a)); \
} while (0)
#define RHASH_UPDATE(hash, key, func, arg) \
- RHASH_UPDATE_ITER(hash, hash_iterating_p(hash), key, func, arg)
+ RHASH_UPDATE_ITER(hash, RHASH_ITER_LEV(hash), key, func, arg)
static void
set_proc_default(VALUE hash, VALUE proc)
@@ -1779,29 +1824,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
@@ -1821,7 +1860,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:
*
@@ -1845,23 +1884,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;
@@ -1899,7 +1927,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);
@@ -1972,12 +2000,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 {
@@ -2015,27 +2040,25 @@ rb_hash_rehash(VALUE hash)
VALUE tmp;
st_table *tbl;
- if (hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) > 0) {
rb_raise(rb_eRuntimeError, "rehash during iteration");
}
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);
}
@@ -2087,15 +2110,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);
@@ -2345,7 +2364,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
@@ -2444,7 +2463,6 @@ 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 {
@@ -2478,7 +2496,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}
@@ -2494,7 +2512,7 @@ rb_hash_shift(VALUE hash)
rb_hash_modify_check(hash);
if (RHASH_AR_TABLE_P(hash)) {
var.key = Qundef;
- if (!hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) == 0) {
if (ar_shift(hash, &var.key, &var.val)) {
return rb_assoc_new(var.key, var.val);
}
@@ -2509,7 +2527,7 @@ rb_hash_shift(VALUE hash)
}
if (RHASH_ST_TABLE_P(hash)) {
var.key = Qundef;
- if (!hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) == 0) {
if (st_shift(RHASH_ST_TABLE(hash), &var.key, &var.val)) {
return rb_assoc_new(var.key, var.val);
}
@@ -2552,7 +2570,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}
@@ -2565,7 +2583,6 @@ 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;
}
@@ -2582,7 +2599,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}
@@ -2613,7 +2630,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') }
@@ -2629,7 +2646,6 @@ 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;
}
@@ -2689,7 +2705,6 @@ rb_hash_except(int argc, VALUE *argv, VALUE hash)
key = argv[i];
rb_hash_delete(result, key);
}
- compact_after_delete(result);
return result;
}
@@ -2698,7 +2713,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]
*
@@ -2724,11 +2739,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:
@@ -2766,11 +2781,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}
@@ -2785,7 +2802,6 @@ 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;
}
@@ -2795,13 +2811,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}
@@ -2832,7 +2850,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}
@@ -2867,7 +2885,7 @@ rb_hash_clear(VALUE hash)
{
rb_hash_modify_check(hash);
- if (hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) > 0) {
rb_hash_foreach(hash, clear_i, 0);
}
else if (RHASH_AR_TABLE_P(hash)) {
@@ -2875,7 +2893,6 @@ rb_hash_clear(VALUE hash)
}
else {
st_clear(RHASH_ST_TABLE(hash));
- compact_after_delete(hash);
}
return hash;
@@ -2916,6 +2933,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+;
@@ -2938,15 +2957,20 @@ NOINSERT_UPDATE_CALLBACK(hash_aset_str)
VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
- bool iter_p = hash_iterating_p(hash);
+ int iter_lev = RHASH_ITER_LEV(hash);
rb_hash_modify(hash);
- if (!RHASH_STRING_KEY_P(hash, key)) {
- RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset, val);
+ if (RHASH_TABLE_NULL_P(hash)) {
+ if (iter_lev > 0) no_new_key();
+ ar_alloc_table(hash);
+ }
+
+ if (RHASH_TYPE(hash) == &identhash || rb_obj_class(key) != rb_cString) {
+ RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset, val);
}
else {
- RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset_str, val);
+ RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset_str, val);
}
return val;
}
@@ -2966,7 +2990,7 @@ rb_hash_replace(VALUE hash, VALUE hash2)
{
rb_hash_modify_check(hash);
if (hash == hash2) return hash;
- if (hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) > 0) {
rb_raise(rb_eRuntimeError, "can't replace hash during iteration");
}
hash2 = to_hash(hash2);
@@ -2974,13 +2998,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;
}
@@ -2991,9 +3021,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
@@ -3043,7 +3073,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 }
@@ -3082,7 +3112,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 }
@@ -3124,6 +3154,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}
@@ -3132,7 +3164,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}"}
@@ -3215,7 +3247,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 }
@@ -3306,7 +3338,6 @@ 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;
}
@@ -3340,7 +3371,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}
@@ -3357,7 +3388,6 @@ 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;
@@ -3372,7 +3402,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}
@@ -3402,8 +3432,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]]
*/
@@ -3456,11 +3486,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
@@ -3528,8 +3558,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}
@@ -3559,12 +3589,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);
@@ -3573,7 +3603,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);
}
@@ -3603,7 +3633,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]
*/
@@ -3620,14 +3650,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);
});
}
@@ -3647,11 +3677,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));
@@ -3674,6 +3706,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+.
*/
@@ -3835,10 +3869,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
@@ -3890,9 +3924,18 @@ 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)
{
- rb_hash_aset(hash, key, value);
+ RHASH_UPDATE(hash, key, rb_hash_update_callback, value);
return ST_CONTINUE;
}
@@ -3904,9 +3947,6 @@ 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;
}
@@ -3930,6 +3970,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.
@@ -4099,17 +4141,24 @@ assoc_cmp(VALUE a, VALUE b)
return !RTEST(rb_equal(a, b));
}
-struct assoc_arg {
- st_table *tbl;
- st_data_t key;
+static VALUE
+lookup2_call(VALUE arg)
+{
+ VALUE *args = (VALUE *)arg;
+ return rb_hash_lookup2(args[0], args[1], Qundef);
+}
+
+struct reset_hash_type_arg {
+ VALUE hash;
+ const struct st_hash_type *orighash;
};
static VALUE
-assoc_lookup(VALUE arg)
+reset_hash_type(VALUE arg)
{
- struct assoc_arg *p = (struct assoc_arg*)arg;
- st_data_t data;
- if (st_lookup(p->tbl, p->key, &data)) return (VALUE)data;
+ struct reset_hash_type_arg *p = (struct reset_hash_type_arg *)arg;
+ HASH_ASSERT(RHASH_ST_TABLE_P(p->hash));
+ RHASH_ST_TABLE(p->hash)->type = p->orighash;
return Qundef;
}
@@ -4129,7 +4178,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]
*
@@ -4139,30 +4188,30 @@ assoc_i(VALUE key, VALUE val, VALUE arg)
static VALUE
rb_hash_assoc(VALUE hash, VALUE key)
{
+ st_table *table;
+ const struct st_hash_type *orighash;
VALUE args[2];
if (RHASH_EMPTY_P(hash)) return Qnil;
- if (RHASH_ST_TABLE_P(hash) && !RHASH_IDENTHASH_P(hash)) {
- VALUE value = Qundef;
- st_table assoctable = *RHASH_ST_TABLE(hash);
- assoctable.type = &(struct st_hash_type){
- .compare = assoc_cmp,
- .hash = assoctable.type->hash,
- };
- VALUE arg = (VALUE)&(struct assoc_arg){
- .tbl = &assoctable,
- .key = (st_data_t)key,
- };
-
- if (RB_OBJ_FROZEN(hash)) {
- value = assoc_lookup(arg);
- }
- else {
- hash_iter_lev_inc(hash);
- value = rb_ensure(assoc_lookup, arg, hash_foreach_ensure, hash);
- }
- hash_verify(hash);
+ ar_force_convert_table(hash, __FILE__, __LINE__);
+ HASH_ASSERT(RHASH_ST_TABLE_P(hash));
+ table = RHASH_ST_TABLE(hash);
+ orighash = table->type;
+
+ if (orighash != &identhash) {
+ VALUE value;
+ struct reset_hash_type_arg ensure_arg;
+ struct st_hash_type assochash;
+
+ assochash.compare = assoc_cmp;
+ assochash.hash = orighash->hash;
+ table->type = &assochash;
+ args[0] = hash;
+ args[1] = key;
+ ensure_arg.hash = hash;
+ ensure_arg.orighash = orighash;
+ value = rb_ensure(lookup2_call, (VALUE)&args, reset_hash_type, (VALUE)&ensure_arg);
if (!UNDEF_P(value)) return rb_assoc_new(key, value);
}
@@ -4188,7 +4237,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}
@@ -4225,7 +4274,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+.
*
* ---
*
@@ -4233,7 +4282,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]]]
@@ -4293,6 +4342,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
@@ -4306,13 +4364,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);
- compact_after_delete(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;
}
@@ -4342,6 +4396,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
@@ -4379,33 +4435,16 @@ rb_hash_compare_by_id(VALUE hash)
if (rb_hash_compare_by_id_p(hash)) return hash;
rb_hash_modify_check(hash);
- if (hash_iterating_p(hash)) {
- rb_raise(rb_eRuntimeError, "compare_by_identity during iteration");
- }
-
- if (RHASH_TABLE_EMPTY_P(hash)) {
- // Fast path: There's nothing to rehash, so we don't need a `tmp` table.
- // We're most likely an AR table, so this will need an allocation.
- ar_force_convert_table(hash, __FILE__, __LINE__);
- HASH_ASSERT(RHASH_ST_TABLE_P(hash));
-
- RHASH_ST_TABLE(hash)->type = &identhash;
- }
- else {
- // Slow path: Need to rehash the members of `self` into a new
- // `tmp` table using the new `identhash` compare/hash functions.
- tmp = hash_alloc(0);
- hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash));
- identtable = RHASH_ST_TABLE(tmp);
-
- rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
- rb_hash_free(hash);
+ ar_force_convert_table(hash, __FILE__, __LINE__);
+ HASH_ASSERT(RHASH_ST_TABLE_P(hash));
- // We know for sure `identtable` is an st table,
- // so we can skip `ar_force_convert_table` here.
- RHASH_ST_TABLE_SET(hash, identtable);
- RHASH_ST_CLEAR(tmp);
- }
+ tmp = hash_alloc(0);
+ 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);
return hash;
}
@@ -4417,17 +4456,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_IDENTHASH_P(hash));
+ return RBOOL(RHASH_ST_TABLE_P(hash) && RHASH_ST_TABLE(hash)->type == &identhash);
}
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;
}
@@ -4435,7 +4474,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;
}
@@ -4445,6 +4484,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)
{
@@ -4487,9 +4532,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.
*
@@ -4508,8 +4550,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
@@ -4687,7 +4727,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
@@ -4701,7 +4741,6 @@ rb_hash_to_proc(VALUE hash)
return rb_func_lambda_new(hash_proc_call, hash, 1, 1);
}
-/* :nodoc: */
static VALUE
rb_hash_deconstruct_keys(VALUE hash, VALUE keys)
{
@@ -4732,13 +4771,14 @@ 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_force_convert_table(hash, __FILE__, __LINE__);
+ ar_try_convert_table(hash);
}
-
tbl = RHASH_TBL_RAW(hash);
return st_update(tbl, (st_data_t)key, add_new_i, (st_data_t)args);
@@ -4771,6 +4811,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);
@@ -4873,7 +4922,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);
@@ -4905,7 +4956,7 @@ env_name(volatile VALUE *s)
static VALUE env_aset(VALUE nm, VALUE val);
static void
-reset_by_modified_env(const char *nam, const char *val)
+reset_by_modified_env(const char *nam)
{
/*
* ENV['TZ'] = nil has a special meaning.
@@ -4914,7 +4965,7 @@ reset_by_modified_env(const char *nam, const char *val)
* This hack might works only on Linux glibc.
*/
if (ENVMATCH(nam, TZ_ENV)) {
- ruby_reset_timezone(val);
+ ruby_reset_timezone();
}
}
@@ -4922,7 +4973,7 @@ static VALUE
env_delete(VALUE name)
{
const char *nam = env_name(name);
- reset_by_modified_env(nam, NULL);
+ reset_by_modified_env(nam);
VALUE val = getenv_with_lock(nam);
if (!NIL_P(val)) {
@@ -5196,7 +5247,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
@@ -5213,7 +5264,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
@@ -5230,7 +5281,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);
}
@@ -5256,7 +5307,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 */
@@ -5320,6 +5371,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].
@@ -5380,7 +5433,7 @@ env_aset(VALUE nm, VALUE val)
get_env_ptr(value, val);
ruby_setenv(name, value);
- reset_by_modified_env(name, value);
+ reset_by_modified_env(name);
return val;
}
@@ -5560,7 +5613,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"}
@@ -5696,7 +5749,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].
@@ -5721,6 +5774,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')
@@ -5764,6 +5819,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:
@@ -5931,23 +5988,24 @@ 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) {
- const char *s = strchr(*env, '=');
+ char *s = strchr(*env, '=');
if (env != environ) {
rb_str_buf_cat2(str, ", ");
}
if (s) {
- 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)));
+ 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);
}
env++;
}
@@ -6073,6 +6131,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
@@ -6553,6 +6613,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"}
@@ -6644,8 +6706,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
@@ -6655,14 +6717,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}
@@ -6787,7 +6849,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:
*
@@ -6846,9 +6908,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
@@ -6862,9 +6924,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
@@ -6887,7 +6949,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
*
@@ -6945,7 +7007,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.
@@ -6985,10 +7047,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:
@@ -7046,7 +7104,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
*
@@ -7059,7 +7117,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.
*
@@ -7224,15 +7282,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
*
@@ -7282,24 +7340,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
*
@@ -7359,8 +7417,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.
@@ -7449,7 +7507,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/atomic.h b/include/ruby/atomic.h
index eb106631f6..3eb80fbf7d 100644
--- a/include/ruby/atomic.h
+++ b/include/ruby/atomic.h
@@ -139,15 +139,6 @@ typedef unsigned int rb_atomic_t;
rbimpl_atomic_cas(&(var), (oldval), (newval))
/**
- * Atomic load. This loads `var` with an atomic intrinsic and returns
- * its value.
- *
- * @param var A variable of ::rb_atomic_t
- * @return What was stored in `var`j
- */
-#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var))
-
-/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except for the return type.
*
* @param var A variable of ::rb_atomic_t.
@@ -289,17 +280,6 @@ typedef unsigned int rb_atomic_t;
RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val))
/**
- * Identical to #RUBY_ATOMIC_LOAD, except it expects its arguments are `void*`.
- * There are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This
- * should be used for size related operations to support such platforms.
- *
- * @param var A variable of `void*`
- * @return The value of `var` (without tearing)
- */
-#define RUBY_ATOMIC_PTR_LOAD(var) \
- RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var))
-
-/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `void*`.
* There are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This
* should be used for size related operations to support such platforms.
@@ -769,21 +749,6 @@ rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val)
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
-static inline rb_atomic_t
-rbimpl_atomic_load(volatile rb_atomic_t *ptr)
-{
-#if 0
-
-#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
-#else
- return rbimpl_atomic_fetch_add(ptr, 0);
-#endif
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_NOALIAS()
-RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_set(volatile rb_atomic_t *ptr, rb_atomic_t val)
{
@@ -910,22 +875,6 @@ rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
-static inline void *
-rbimpl_atomic_ptr_load(void **ptr)
-{
-#if 0
-
-#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
-#else
- void *val = *ptr;
- return rbimpl_atomic_ptr_cas(ptr, val, val);
-#endif
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_NOALIAS()
-RBIMPL_ATTR_NONNULL((1))
static inline VALUE
rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval)
{
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 f7c8e6ca8d..f95acdb17e 100644
--- a/include/ruby/debug.h
+++ b/include/ruby/debug.h
@@ -10,7 +10,6 @@
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
*/
-#include "ruby/internal/attr/deprecated.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/returns_nonnull.h"
#include "ruby/internal/dllexport.h"
@@ -52,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.
@@ -616,157 +596,48 @@ VALUE rb_tracearg_object(rb_trace_arg_t *trace_arg);
/*
* Postponed Job API
- *
- * This API is designed to be called from contexts where it is not safe to run Ruby
- * code (e.g. because they do not hold the GVL or because GC is in progress), and
- * defer a callback to run in a context where it _is_ safe. The primary intended
- * users of this API is for sampling profilers like the "stackprof" gem; these work
- * by scheduling the periodic delivery of a SIGPROF signal, and inside the C-level
- * signal handler, deferring a job to collect a Ruby backtrace when it is next safe
- * to do so.
- *
- * Ruby maintains a small, fixed-size postponed job table. An extension using this
- * API should first call `rb_postponed_job_preregister` to register a callback
- * function in this table and obtain a handle of type `rb_postponed_job_handle_t`
- * to it. Subsequently, the callback can be triggered by calling
- * `rb_postponed_job_trigger` with that handle, or the `data` associated with the
- * callback function can be changed by calling `rb_postponed_job_preregister` again.
- *
- * Because the postponed job table is quite small (it only has 32 entries on most
- * common systems), extensions should generally only preregister one or two `func`
- * values.
- *
- * Historically, this API provided two functions `rb_postponed_job_register` and
- * `rb_postponed_job_register_one`, which claimed to be fully async-signal-safe and
- * would call back the provided `func` and `data` at an appropriate time. However,
- * these functions were subject to race conditions which could cause crashes when
- * racing with Ruby's internal use of them. These two functions are still present,
- * but are marked as deprecated and have slightly changed semantics:
- *
- * * rb_postponed_job_register now works like rb_postponed_job_register_one i.e.
- * `func` will only be executed at most one time each time Ruby checks for
- * interrupts, no matter how many times it is registered
- * * They are also called with the last `data` to be registered, not the first
- * (which is how rb_postponed_job_register_one previously worked)
+ * rb_postponed_job_register and rb_postponed_job_register_one are
+ * async-signal-safe and used via SIGPROF by the "stackprof" RubyGem
*/
-
/**
* Type of postponed jobs.
*
- * @param[in,out] arg What was passed to `rb_postponed_job_preregister`
+ * @param[in,out] arg What was passed to rb_postponed_job_register().
*/
typedef void (*rb_postponed_job_func_t)(void *arg);
/**
- * The type of a handle returned from `rb_postponed_job_preregister` and
- * passed to `rb_postponed_job_trigger`
- */
-typedef unsigned int rb_postponed_job_handle_t;
-#define POSTPONED_JOB_HANDLE_INVALID ((rb_postponed_job_handle_t)UINT_MAX)
-
-/**
- * Pre-registers a func in Ruby's postponed job preregistration table,
- * returning an opaque handle which can be used to trigger the job later. Generally,
- * this function will be called during the initialization routine of an extension.
+ * Registers a postponed job.
*
- * The returned handle can be used later to call `rb_postponed_job_trigger`. This will
- * cause Ruby to call back into the registered `func` with `data` at a later time, in
- * a context where the GVL is held and it is safe to perform Ruby allocations.
+ * There are situations when running a ruby program is not possible. For
+ * instance when a program is in a signal handler; for another instance when
+ * the GC is busy. On such situations however, there might be needs to do
+ * something. We cannot but defer such operations until we are 100% sure it is
+ * safe to execute them. This mechanism is called postponed jobs. This
+ * function registers a new one. The registered job would eventually gets
+ * executed.
*
- * If the given `func` was already pre-registered, this function will overwrite the
- * stored data with the newly passed data, and return the same handle instance as
- * was previously returned.
- *
- * If this function is called concurrently with the same `func`, then the stored data
- * could be the value from either call (but will definitely be one of them).
- *
- * If this function is called to update the data concurrently with a call to
- * `rb_postponed_job_trigger` on the same handle, it's undefined whether `func` will
- * be called with the old data or the new data.
- *
- * Although the current implementation of this function is in fact async-signal-safe and
- * has defined semantics when called concurrently on the same `func`, a future Ruby
- * version might require that this method be called under the GVL; thus, programs which
- * aim to be forward-compatible should call this method whilst holding the GVL.
- *
- * @param[in] flags Unused and ignored
- * @param[in] func The function to be pre-registered
- * @param[in] data The data to be pre-registered
- * @retval POSTPONED_JOB_HANDLE_INVALID The job table is full; this registration
- * did not succeed and no further registration will do so for
- * the lifetime of the program.
- * @retval otherwise A handle which can be passed to `rb_postponed_job_trigger`
- */
-rb_postponed_job_handle_t rb_postponed_job_preregister(unsigned int flags, rb_postponed_job_func_t func, void *data);
-
-/**
- * Triggers a pre-registered job registered with rb_postponed_job_preregister,
- * scheduling it for execution the next time the Ruby VM checks for interrupts.
- * The context in which the job is called in holds the GVL and is safe to perform
- * Ruby allocations within (i.e. it is not during GC).
- *
- * This method is async-signal-safe and can be called from any thread, at any
- * time, including in signal handlers.
- *
- * If this method is called multiple times, Ruby will coalesce this into only
- * one call to the job the next time it checks for interrupts.
- *
- * @params[in] h A handle returned from rb_postponed_job_preregister
- */
-void rb_postponed_job_trigger(rb_postponed_job_handle_t h);
-
-/**
- * Schedules the given `func` to be called with `data` when Ruby next checks for
- * interrupts. If this function is called multiple times in between Ruby checking
- * for interrupts, then `func` will be called only once with the `data` value from
- * the first call to this function.
- *
- * Like `rb_postponed_job_trigger`, the context in which the job is called
- * holds the GVL and can allocate Ruby objects.
- *
- * This method essentially has the same semantics as:
- *
- * ```
- * rb_postponed_job_trigger(rb_postponed_job_preregister(func, data));
- * ```
- *
- * @note Previous versions of Ruby promised that the (`func`, `data`) pairs would
- * be executed as many times as they were registered with this function; in
- * reality this was always subject to race conditions and this function no
- * longer provides this guarantee. Instead, multiple calls to this function
- * can be coalesced into a single execution of the passed `func`, with the
- * most recent `data` registered at that time passed in.
- *
- * @deprecated This interface implies that arbitrarily many `func`'s can be enqueued
- * over the lifetime of the program, whilst in reality the registration
- * slots for postponed jobs are a finite resource. This is made clearer
- * by the `rb_postponed_job_preregister` and `rb_postponed_job_trigger`
- * functions, and a future version of Ruby might delete this function.
- *
- * @param[in] flags Unused and ignored.
+ * @param[in] flags (Unused) reserved for future extensions.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
- * @retval 0 Postponed job registration table is full. Failed.
- * @retval 1 Registration succeeded.
- * @post The passed job will run on the next interrupt check.
+ * @retval 0 Postponed job buffer is full. Failed.
+ * @retval otherwise Opaque return value.
+ * @post The passed job is postponed.
*/
- RBIMPL_ATTR_DEPRECATED(("use rb_postponed_job_preregister and rb_postponed_job_trigger"))
int rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data);
/**
- * Identical to `rb_postponed_job_register`
- *
- * @deprecated This is deprecated for the same reason as `rb_postponed_job_register`
+ * 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 and ignored.
+ * @param[in] flags (Unused) reserved for future extensions.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
- * @retval 0 Postponed job registration table is full. Failed.
- * @retval 1 Registration succeeded.
- * @post The passed job will run on the next interrupt check.
+ * @retval 0 Postponed job buffer is full. Failed.
+ * @retval otherwise Opaque return value.
*/
- RBIMPL_ATTR_DEPRECATED(("use rb_postponed_job_preregister and rb_postponed_job_trigger"))
int rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data);
/** @} */
diff --git a/include/ruby/fiber/scheduler.h b/include/ruby/fiber/scheduler.h
index 8f3d383330..250b39b6df 100644
--- a/include/ruby/fiber/scheduler.h
+++ b/include/ruby/fiber/scheduler.h
@@ -97,7 +97,7 @@ VALUE rb_fiber_scheduler_get(void);
* current thread will call scheduler's `#close` method on finalisation
* (allowing the scheduler to properly manage all non-finished fibers).
* `scheduler` can be an object of any class corresponding to
- * `Fiber::Scheduler` interface. Its implementation is up to the user.
+ * `Fiber::SchedulerInterface`. Its implementation is up to the user.
*
* @param[in] scheduler The scheduler to set.
* @exception rb_eArgError `scheduler` does not conform the interface.
@@ -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/attr/noexcept.h b/include/ruby/internal/attr/noexcept.h
index 7c3f92f1e7..ea3001df2a 100644
--- a/include/ruby/internal/attr/noexcept.h
+++ b/include/ruby/internal/attr/noexcept.h
@@ -54,7 +54,7 @@
* get smarter and smarter. Today they can infer if it actually throws
* or not without any annotations by humans (correct me if I'm wrong).
*
- * - When an inline function attributed `noexcept` actually _does_ throw an
+ * - When an inline function attributed `noexcepr` actually _does_ throw an
* exception: they have to call `std::terminate` then (C++ standard
* mandates so). This means exception handling routines are actually
* enforced, not omitted. This doesn't impact runtime performance (The
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 44b3e8cc0f..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,
@@ -457,7 +489,7 @@ RB_FL_ABLE(VALUE obj)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_TEST(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_TEST(). 3rd parties need not use
* this. Just always use RB_FL_TEST().
*
* @param[in] obj Object in question.
@@ -505,7 +537,7 @@ RB_FL_TEST(VALUE obj, VALUE flags)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_ANY(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_ANY(). 3rd parties need not use
* this. Just always use RB_FL_ANY().
*
* @param[in] obj Object in question.
@@ -539,7 +571,7 @@ RB_FL_ANY(VALUE obj, VALUE flags)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_ALL(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_ALL(). 3rd parties need not use
* this. Just always use RB_FL_ALL().
*
* @param[in] obj Object in question.
@@ -575,7 +607,7 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implementation detail of RB_FL_SET(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_SET(). 3rd parties need not use
* this. Just always use RB_FL_SET().
*
* @param[out] obj Object in question.
@@ -595,7 +627,7 @@ rbimpl_fl_set_raw_raw(struct RBasic *obj, VALUE flags)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_SET(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_SET(). 3rd parties need not use
* this. Just always use RB_FL_SET().
*
* @param[out] obj Object in question.
@@ -635,7 +667,7 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implementation detail of RB_FL_UNSET(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_UNSET(). 3rd parties need not use
* this. Just always use RB_FL_UNSET().
*
* @param[out] obj Object in question.
@@ -655,7 +687,7 @@ rbimpl_fl_unset_raw_raw(struct RBasic *obj, VALUE flags)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_UNSET(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_UNSET(). 3rd parties need not use
* this. Just always use RB_FL_UNSET().
*
* @param[out] obj Object in question.
@@ -690,7 +722,7 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implementation detail of RB_FL_REVERSE(). 3rd parties need not
+ * This is an implenentation detail of RB_FL_REVERSE(). 3rd parties need not
* use this. Just always use RB_FL_REVERSE().
*
* @param[out] obj Object in question.
@@ -710,7 +742,7 @@ rbimpl_fl_reverse_raw_raw(struct RBasic *obj, VALUE flags)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_REVERSE(). 3rd parties need not
+ * This is an implenentation detail of RB_FL_REVERSE(). 3rd parties need not
* use this. Just always use RB_FL_REVERSE().
*
* @param[out] obj Object in question.
@@ -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,15 +883,13 @@ 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;
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_OBJ_FROZEN(). 3rd parties need not
+ * This is an implenentation detail of RB_OBJ_FROZEN(). 3rd parties need not
* use this. Just always use RB_OBJ_FROZEN().
*
* @param[in] obj Object in question.
@@ -907,7 +930,7 @@ RB_OBJ_FROZEN(VALUE obj)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_OBJ_FREEZE(). 3rd parties need not
+ * This is an implenentation detail of RB_OBJ_FREEZE(). 3rd parties need not
* use this. Just always use RB_OBJ_FREEZE().
*
* @param[out] obj Object in question.
diff --git a/include/ruby/internal/gc.h b/include/ruby/internal/gc.h
index ac9dfd8842..66fc14e511 100644
--- a/include/ruby/internal/gc.h
+++ b/include/ruby/internal/gc.h
@@ -20,395 +20,16 @@
* 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 RUBY_REF_EDGE(s, p) offsetof(s, p)
-#define RUBY_REFS_LIST_PTR(l) (RUBY_DATA_FUNC)(l)
-#define RUBY_REF_END SIZE_MAX
-#define RUBY_REFERENCES(t) static const size_t t[]
-#define RUBY_REFERENCES_START(t) RUBY_REFERENCES(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
- * extensions should use this API on global constants instead of assuming
- * constants defined in Ruby are always alive. Ruby code can remove global
- * constants.
- *
- * Because this registration itself has a possibility to trigger a GC, this
- * function must be called before any GC-able objects is assigned to the
- * address pointed by `valptr`.
+ * Inform the garbage collector that `valptr` points to a live Ruby object that
+ * should not be moved. Note that extensions should use this API on global
+ * constants instead of assuming constants defined in Ruby are always alive.
+ * Ruby code can remove global constants.
*/
void rb_gc_register_address(VALUE *valptr);
@@ -433,410 +54,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/globals.h b/include/ruby/internal/globals.h
index 60d8e5309a..5a414fc472 100644
--- a/include/ruby/internal/globals.h
+++ b/include/ruby/internal/globals.h
@@ -94,7 +94,7 @@ RUBY_EXTERN VALUE rb_cRegexp; /**< `Regexp` class. */
RUBY_EXTERN VALUE rb_cStat; /**< `File::Stat` class. */
RUBY_EXTERN VALUE rb_cString; /**< `String` class. */
RUBY_EXTERN VALUE rb_cStruct; /**< `Struct` class. */
-RUBY_EXTERN VALUE rb_cSymbol; /**< `Symbol` class. */
+RUBY_EXTERN VALUE rb_cSymbol; /**< `Sumbol` class. */
RUBY_EXTERN VALUE rb_cThread; /**< `Thread` class. */
RUBY_EXTERN VALUE rb_cTime; /**< `Time` class. */
RUBY_EXTERN VALUE rb_cTrueClass; /**< `TrueClass` class. */
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/array.h b/include/ruby/internal/intern/array.h
index 1909fdf17b..2262c6f0c6 100644
--- a/include/ruby/internal/intern/array.h
+++ b/include/ruby/internal/intern/array.h
@@ -187,7 +187,7 @@ VALUE rb_ary_shared_with_p(VALUE lhs, VALUE rhs);
* : (int i) -> T?
* | (int beg, int len) -> ::Array[T]?
* | (Range[int] r) -> ::Array[T]?
- * | (ArithmeticSequence as) -> ::Array[T]? # This also raises RangeError.
+ * | (ArithmeticSequence as) -> ::Array[T]? # This also raises RagneError.
* end
* ```
*/
diff --git a/include/ruby/internal/intern/bignum.h b/include/ruby/internal/intern/bignum.h
index c27f77a1fb..43d68018de 100644
--- a/include/ruby/internal/intern/bignum.h
+++ b/include/ruby/internal/intern/bignum.h
@@ -51,7 +51,7 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
VALUE rb_big_new(size_t len, int sign);
/**
- * Queries if the passed bignum instance is a "bigzero". What is a bigzero?
+ * Queries if the passed bignum instance is a "bigzro". What is a bigzero?
* Well, bignums are for very big integers, but can also represent tiny ones
* like -1, 0, 1. Bigzero are instances of bignums whose values are zero.
* Knowing if a bignum is bigzero can be handy on occasions, like for instance
@@ -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/load.h b/include/ruby/internal/intern/load.h
index 9ceb98c2e4..288a16c2ec 100644
--- a/include/ruby/internal/intern/load.h
+++ b/include/ruby/internal/intern/load.h
@@ -177,43 +177,6 @@ VALUE rb_f_require(VALUE self, VALUE feature);
VALUE rb_require_string(VALUE feature);
/**
- * Resolves and returns a symbol of a function in the native extension
- * specified by the feature and symbol names. Extensions will use this function
- * to access the symbols provided by other native extensions.
- *
- * @param[in] feature Name of a feature, e.g. `"json"`.
- * @param[in] symbol Name of a symbol defined by the feature.
- * @return The resolved symbol of a function, defined and externed by the
- * specified feature. It may be NULL if the feature is not loaded,
- * the feature is not extension, or the symbol is not found.
- */
-void *rb_ext_resolve_symbol(const char *feature, const char *symbol);
-
-/**
- * This macro is to provide backwards compatibility. It provides a way to
- * define function prototypes and resolving function symbols in a safe way.
- *
- * ```CXX
- * // prototypes
- * #ifdef HAVE_RB_EXT_RESOLVE_SYMBOL
- * VALUE *(*other_extension_func)(VALUE,VALUE);
- * #else
- * VALUE other_extension_func(VALUE);
- * #endif
- *
- * // in Init_xxx()
- * #ifdef HAVE_RB_EXT_RESOLVE_SYMBOL
- * other_extension_func = \
- * (VALUE(*)(VALUE,VALUE))rb_ext_resolve_symbol(fname, sym_name);
- * if (other_extension_func == NULL) {
- * // raise your own error
- * }
- * #endif
- * ```
- */
-#define HAVE_RB_EXT_RESOLVE_SYMBOL 1
-
-/**
* @name extension configuration
* @{
*/
diff --git a/include/ruby/internal/intern/process.h b/include/ruby/internal/intern/process.h
index cfa5e13162..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)`.
@@ -256,7 +247,7 @@ rb_pid_t rb_spawn_err(int argc, const VALUE *argv, char *errbuf, size_t buflen);
*
* @internal
*
- * This function might or might not exist depending on `./configure` result.
+ * This function might or might not exist depending on `./confiugre` result.
* It must be a portability hell. Better not use.
*/
VALUE rb_proc_times(VALUE _);
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/select.h b/include/ruby/internal/intern/select.h
index 6ba84c6e63..fabc287cd1 100644
--- a/include/ruby/internal/intern/select.h
+++ b/include/ruby/internal/intern/select.h
@@ -76,7 +76,7 @@ struct timeval;
*
* Although any file descriptors are possible here, it makes completely no
* sense to pass a descriptor that is not `O_NONBLOCK`. If you want to know
- * the reason for this limitation in detail, you might find this thread super
+ * the reason for this limitatuon in detail, you might find this thread super
* interesting: https://lkml.org/lkml/2004/10/6/117
*/
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout);
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/memory.h b/include/ruby/internal/memory.h
index 8f00787512..6884db195d 100644
--- a/include/ruby/internal/memory.h
+++ b/include/ruby/internal/memory.h
@@ -62,7 +62,7 @@
#include "ruby/backward/2/assume.h"
#include "ruby/defines.h"
-/** @cond INTERNAL_MACRO */
+/** @cond INTENAL_MACRO */
/* Make alloca work the best possible way. */
#if defined(alloca)
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 e4d98bf051..88e5598066 100644
--- a/include/ruby/io/buffer.h
+++ b/include/ruby/io/buffer.h
@@ -23,18 +23,10 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
#define RUBY_IO_BUFFER_VERSION 2
-// The `IO::Buffer` class.
RUBY_EXTERN VALUE rb_cIOBuffer;
-
-// The operating system page size.
RUBY_EXTERN size_t RUBY_IO_BUFFER_PAGE_SIZE;
-
-// The default buffer size, usually a (small) multiple of the page size.
-// Can be overridden by the RUBY_IO_BUFFER_DEFAULT_SIZE environment variable.
RUBY_EXTERN size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
-// Represents the internal state of the buffer.
-// More than one flag can be set at a time.
enum rb_io_buffer_flags {
// The memory in the buffer is owned by someone else.
// More specifically, it means that someone else owns the buffer and we shouldn't try to resize it.
@@ -57,22 +49,21 @@ enum rb_io_buffer_flags {
RB_IO_BUFFER_PRIVATE = 64,
// The buffer is read-only and cannot be modified.
- RB_IO_BUFFER_READONLY = 128,
-
- // The buffer is backed by a file.
- RB_IO_BUFFER_FILE = 256,
+ RB_IO_BUFFER_READONLY = 128
};
-// Represents the endian of the data types.
enum rb_io_buffer_endian {
- // The least significant units are put first.
RB_IO_BUFFER_LITTLE_ENDIAN = 4,
RB_IO_BUFFER_BIG_ENDIAN = 8,
-#if defined(WORDS_BIGENDIAN)
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_LITTLE_ENDIAN,
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN,
-#else
+#elif REG_DWORD == REG_DWORD_LITTLE_ENDIAN
RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_LITTLE_ENDIAN,
+#elif 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
@@ -84,14 +75,9 @@ 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);
-// Access the internal buffer and flags. Validates the pointers.
-// The points may not remain valid if the source buffer is manipulated.
-// Consider using rb_io_buffer_lock if needed.
-enum rb_io_buffer_flags rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size);
+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);
void rb_io_buffer_get_bytes_for_writing(VALUE self, 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 db290cd47a..8d7c601703 100644
--- a/include/ruby/onigmo.h
+++ b/include/ruby/onigmo.h
@@ -636,7 +636,6 @@ ONIG_EXTERN const OnigSyntaxType* OnigDefaultSyntax;
#define ONIGERR_PARSE_DEPTH_LIMIT_OVER -16
#define ONIGERR_DEFAULT_ENCODING_IS_NOT_SET -21
#define ONIGERR_SPECIFIED_ENCODING_CANT_CONVERT_TO_WIDE_CHAR -22
-#define ONIGERR_TIMEOUT -23
/* general error */
#define ONIGERR_INVALID_ARGUMENT -30
/* syntax error */
@@ -745,6 +744,8 @@ typedef struct {
typedef struct {
int lower;
int upper;
+ long base_num;
+ long inner_num;
} OnigRepeatRange;
typedef void (*OnigWarnFunc)(const char* s);
@@ -845,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/random.h b/include/ruby/random.h
index f3df0d96fb..39bdb6f3e3 100644
--- a/include/ruby/random.h
+++ b/include/ruby/random.h
@@ -11,7 +11,7 @@
*
* This is a set of APIs to roll your own subclass of ::rb_cRandom. An
* illustrative example of such PRNG can be found at
- * `ext/-test-/random/loop.c`.
+ * `ext/-test-/ramdom/loop.c`.
*/
#include "ruby/ruby.h"
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 035f02c70b..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,124 +271,6 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 0)
*/
int ruby_vsnprintf(char *str, size_t n, char const *fmt, va_list ap);
-#include <errno.h>
-
-/**
- * @name Errno handling routines for userland threads
- * @note POSIX chapter 2 section 3 states that for each thread of a process,
- * the value of `errno` shall not be affected by function calls or
- * assignments to `errno` by other threads.
- *
- * Soooo this `#define errno` below seems like a noob mistake at first sight.
- * If you look at its actual implementation, the functions are just adding one
- * level of indirection. It doesn't make any sense sorry? But yes! @ko1 told
- * @shyouhei that this is inevitable.
- *
- * The ultimate reason is because Ruby now has N:M threads implemented.
- * Threads of that sort change their context in user land. A function can be
- * "transferred" between threads in middle of their executions. Let us for
- * instance consider:
- *
- * ```cxx
- * void foo()
- * {
- * auto i = errno;
- * close(0);
- * errno = i;
- * }
- * ```
- *
- * This function (if ran under our Ractor) could change its running thread at
- * the `close` function. But the two `errno` invocations are different! Look
- * how the source code above is compiled by clang 17 with `-O3` flag @ Linux:
- *
- * ```
- * foo(int): # @foo(int)
- * push rbp
- * push r14
- * push rbx
- * mov ebx, edi
- * call __errno_location@PLT
- * mov r14, rax
- * mov ebp, dword ptr [rax]
- * mov edi, ebx
- * call close@PLT
- * mov dword ptr [r14], ebp
- * pop rbx
- * pop r14
- * pop rbp
- * ret
- * ```
- *
- * Notice how `__errno_location@PLT` is `call`-ed only once. The compiler
- * assumes that the location of `errno` does not change during a function call.
- * Sadly this is no longer true for us. The `close@PLT` now changes threads,
- * which should also change where `errno` is stored.
- *
- * With the `#define errno` below the compilation result changes to this:
- *
- * ```
- * foo(int): # @foo(int)
- * push rbp
- * push rbx
- * push rax
- * mov ebx, edi
- * call rb_errno_ptr()@PLT
- * mov ebp, dword ptr [rax]
- * mov edi, ebx
- * call close@PLT
- * call rb_errno_ptr()@PLT
- * mov dword ptr [rax], ebp
- * add rsp, 8
- * pop rbx
- * pop rbp
- * ret
- * ```
- *
- * Which fixes the problem.
- */
-
-/**
- * Identical to system `errno`.
- *
- * @return The last set `errno` number.
- */
-int rb_errno(void);
-
-/**
- * Set the errno.
- *
- * @param err New `errno`.
- * @post `errno` is now set to `err`.
- */
-void rb_errno_set(int err);
-
-/**
- * The location of `errno`
- *
- * @return The (thread-specific) location of `errno`.
- */
-int *rb_errno_ptr(void);
-
-/**
- * Not sure if it is necessary for extension libraries but this is where the
- * "bare" errno is located.
- *
- * @return The location of `errno`.
- */
-static inline int *
-rb_orig_errno_ptr(void)
-{
- return &errno;
-}
-
-#define rb_orig_errno errno /**< System-provided original `errno`. */
-#undef errno
-#define errno (*rb_errno_ptr()) /**< Ractor-aware version of `errno`. */
-
-/** @} */
-
-
/** @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..1e4bb80686 100644
--- a/include/ruby/st.h
+++ b/include/ruby/st.h
@@ -98,14 +98,10 @@ struct st_table {
enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK, ST_REPLACE};
-size_t rb_st_table_size(const struct st_table *tbl);
-#define st_table_size rb_st_table_size
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 +158,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 f01d276a29..0b5b1ca0f3 100644
--- a/include/ruby/thread.h
+++ b/include/ruby/thread.h
@@ -190,46 +190,14 @@ 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 successfully 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 struct rb_internal_thread_event_data {
- VALUE thread;
-} rb_internal_thread_event_data_t;
+typedef void rb_internal_thread_event_data_t; // for future extension.
typedef void (*rb_internal_thread_event_callback)(rb_event_flag_t event,
const rb_internal_thread_event_data_t *event_data,
@@ -243,12 +211,7 @@ typedef struct rb_internal_thread_event_hook rb_internal_thread_event_hook_t;
* @param[in] events A set of events that `func` should run.
* @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 and WebAssembly.
- * @note The callback will be called without the GVL held, except for the
- * RESUMED event.
- * @note Callbacks are not guaranteed to be executed on the native threads
- * that corresponds to the Ruby thread. To identify which Ruby thread
- * the event refers to, you must use `event_data->thread`.
+ * @note This functionality is a noop on Windows.
* @warning This function MUST not be called from a thread event callback.
*/
rb_internal_thread_event_hook_t *rb_internal_thread_add_event_hook(
@@ -260,53 +223,13 @@ rb_internal_thread_event_hook_t *rb_internal_thread_add_event_hook(
* Unregister the passed hook.
*
* @param[in] hook. The hook to unregister.
- * @return Whether the hook was found and unregistered.
- * @note This functionality is a noop on Windows and WebAssembly.
+ * @return Wether the hook was found and unregistered.
+ * @note This functionality is a noop on Windows.
* @warning This function MUST not be called from a thread event callback.
*/
bool rb_internal_thread_remove_event_hook(
rb_internal_thread_event_hook_t * hook);
-
-typedef int rb_internal_thread_specific_key_t;
-#define RB_INTERNAL_THREAD_SPECIFIC_KEY_MAX 8
-/**
- * Create a key to store thread specific data.
- *
- * These APIs are designed for tools using
- * rb_internal_thread_event_hook APIs.
- *
- * Note that only `RB_INTERNAL_THREAD_SPECIFIC_KEY_MAX` keys
- * can be created. raises `ThreadError` if exceeded.
- *
- * Usage:
- * // at initialize time:
- * int tool_key; // gvar
- * Init_tool() {
- * tool_key = rb_internal_thread_specific_key_create();
- * }
- *
- * // at any timing:
- * rb_internal_thread_specific_set(thread, tool_key, per_thread_data);
- * ...
- * per_thread_data = rb_internal_thread_specific_get(thread, tool_key);
- */
-rb_internal_thread_specific_key_t rb_internal_thread_specific_key_create(void);
-
-/**
- * Get thread and tool specific data.
- *
- * This function is async signal safe and thread safe.
- */
-void *rb_internal_thread_specific_get(VALUE thread_val, rb_internal_thread_specific_key_t key);
-
-/**
- * Set thread and tool specific data.
- *
- * This function is async signal safe and thread safe.
- */
-void rb_internal_thread_specific_set(VALUE thread_val, rb_internal_thread_specific_key_t key, void *data);
-
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RUBY_THREAD_H */
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 12e69c4b80..e8727a3200 100644
--- a/include/ruby/util.h
+++ b/include/ruby/util.h
@@ -33,20 +33,9 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
-/** an approximation of ceil(n * log10(2)), up to 1,048,576 (1<<20)
- * without overflow within 32-bit calculation
- */
+/** 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..197eb8a802 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -147,10 +147,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 +716,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 9ed104f369..e809b56cc9 100644
--- a/inits.c
+++ b/inits.c
@@ -22,6 +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);
@@ -51,18 +56,17 @@ rb_call_inits(void)
CALL(Dir);
CALL(Time);
CALL(Random);
+ CALL(signal);
CALL(load);
CALL(Proc);
CALL(Binding);
CALL(Math);
CALL(GC);
- CALL(WeakMap);
CALL(Enumerator);
CALL(Ractor);
CALL(VM);
CALL(ISeq);
CALL(Thread);
- CALL(signal);
CALL(Fiber_Scheduler);
CALL(process);
CALL(Cont);
@@ -75,7 +79,6 @@ rb_call_inits(void)
CALL(ast);
CALL(gc_stress);
CALL(shape);
- CALL(Prism);
// enable builtin loading
CALL(builtin);
@@ -102,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 5f6cb314ff..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
@@ -498,11 +511,10 @@ expandarray
(rb_num_t num, rb_num_t flag)
(..., VALUE ary)
(...)
-// attr bool handles_sp = true;
// attr bool leaf = false; /* has rb_check_array_type() */
// attr rb_snum_t sp_inc = (rb_snum_t)num - 1 + (flag & 1 ? 1 : 0);
{
- vm_expandarray(GET_CFP(), ary, num, (int)flag);
+ vm_expandarray(GET_SP(), ary, num, (int)flag);
}
/* concat two arrays */
@@ -527,17 +539,6 @@ splatarray
obj = vm_splat_array(flag, ary);
}
-/* call to_hash on hash to keyword splat before converting block */
-DEFINE_INSN
-splatkw
-()
-(VALUE hash, VALUE block)
-(VALUE obj, VALUE block)
-// attr bool leaf = false; /* has rb_to_hash_type() */
-{
- obj = rb_to_hash_type(hash);
-}
-
/* put new Hash from n elements. n must be an even number. */
DEFINE_INSN
newhash
@@ -700,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.
@@ -812,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();
@@ -832,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();
@@ -898,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
@@ -908,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 */
@@ -936,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();
@@ -956,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();
@@ -1363,8 +1345,10 @@ opt_aset_with
val = tmp;
}
else {
+#ifndef MJIT_HEADER
TOPN(0) = rb_str_resurrect(key);
PUSH(val);
+#endif
CALL_SIMPLE_METHOD();
}
}
@@ -1381,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();
}
}
@@ -1471,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 594f1daea7..5731a5bc33 100644
--- a/internal/class.h
+++ b/internal/class.h
@@ -8,19 +8,13 @@
* 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 */
#include "shape.h"
-#include "ruby_assert.h"
-#include "vm_core.h"
-#include "vm_sync.h"
-#include "method.h" /* for rb_cref_t */
#ifdef RCLASS_SUPER
# undef RCLASS_SUPER
@@ -31,12 +25,10 @@ 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;
rb_serial_t global_cvar_state;
- const rb_cref_t * cref;
VALUE class_value;
};
@@ -44,7 +36,7 @@ struct rb_classext_struct {
VALUE *iv_ptr;
struct rb_id_table *const_tbl;
struct rb_id_table *callable_m_tbl;
- struct rb_id_table *cc_tbl; /* ID -> [[ci1, cc1], [ci2, cc2] ...] */
+ struct rb_id_table *cc_tbl; /* ID -> [[ci, cc1], cc2, ...] */
struct rb_id_table *cvc_tbl;
size_t superclass_depth;
VALUE *superclasses;
@@ -58,40 +50,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)
@@ -103,60 +87,16 @@ 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
-static inline st_table *
-RCLASS_IV_HASH(VALUE obj)
-{
- RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
- return (st_table *)RCLASS_IVPTR(obj);
-}
-
-static inline void
-RCLASS_SET_IV_HASH(VALUE obj, const st_table *tbl)
-{
- RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
- RCLASS_IVPTR(obj) = (VALUE *)tbl;
-}
-
-static inline uint32_t
-RCLASS_IV_COUNT(VALUE obj)
-{
- RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- if (rb_shape_obj_too_complex(obj)) {
- uint32_t count;
-
- // "Too complex" classes could have their IV hash mutated in
- // parallel, so lets lock around getting the hash size.
- RB_VM_LOCK_ENTER();
- {
- count = (uint32_t)rb_st_table_size(RCLASS_IV_HASH(obj));
- }
- RB_VM_LOCK_LEAVE();
-
- return count;
- }
- else {
- return rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_iv_index;
- }
-}
-
-static inline void
-RCLASS_SET_M_TBL(VALUE klass, struct rb_id_table *table)
-{
- RUBY_ASSERT(!RB_OBJ_PROMOTED(klass));
- RCLASS_M_TBL(klass) = table;
-}
-
/* class.c */
void rb_class_subclass_add(VALUE super, VALUE klass);
void rb_class_remove_from_super_subclasses(VALUE);
@@ -175,7 +115,6 @@ 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);
@@ -192,24 +131,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)
@@ -254,24 +179,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/cont.h b/internal/cont.h
index 3c2528a02a..c3b091668a 100644
--- a/internal/cont.h
+++ b/internal/cont.h
@@ -22,9 +22,6 @@ void rb_jit_cont_init(void);
void rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data);
void rb_jit_cont_finish(void);
-/* vm.c */
-void rb_free_shared_fiber_pool(void);
-
// Copy locals from the current execution to the specified fiber.
VALUE rb_fiber_inherit_storage(struct rb_execution_context_struct *ec, struct rb_fiber_struct *fiber);
diff --git a/internal/encoding.h b/internal/encoding.h
index 11ffa6d83d..a3b81bd388 100644
--- a/internal/encoding.h
+++ b/internal/encoding.h
@@ -29,7 +29,4 @@ void rb_enc_set_base(const char *name, const char *orig);
int rb_enc_set_dummy(int index);
PUREFUNC(int rb_data_is_encoding(VALUE obj));
-/* vm.c */
-void rb_free_global_enc_table(void);
-
#endif /* INTERNAL_ENCODING_H */
diff --git a/internal/error.h b/internal/error.h
index 7e41f134d7..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;
@@ -169,9 +147,6 @@ VALUE rb_syserr_new_path_in(const char *func_name, int n, VALUE path);
#endif
RUBY_SYMBOL_EXPORT_END
-/* vm.c */
-void rb_free_warning(void);
-
static inline void
rb_raise_cstr_i(VALUE etype, VALUE mesg)
{
diff --git a/internal/eval.h b/internal/eval.h
index e594d8516d..73bb656d96 100644
--- a/internal/eval.h
+++ b/internal/eval.h
@@ -21,7 +21,6 @@ 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 34a6043e8a..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 NEWOBJ_OF(var, T, c, f, s, ec) \
- NEWOBJ_OF_HELPER(ec)(var, T, c, f, s, ec)
+#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_HELPER(ec) NEWOBJ_OF_ ## ec
+/* optimized version of NEWOBJ() */
+#define RB_NEWOBJ_OF(var, T, c, f) RB_RVARGC_NEWOBJ_OF(var, T, c, f, RVALUE_SIZE)
+#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,63 +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);
-
-void rb_gc_ref_update_table_values_only(st_table *tbl);
-
-#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)
@@ -321,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 *
@@ -350,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..657e5eff3c 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))
@@ -75,8 +73,6 @@ VALUE rb_hash_default_value(VALUE hash, VALUE key);
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 +82,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 +95,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 +106,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 +116,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 +202,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 +214,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 903e2d29a5..7b54e13dd2 100644
--- a/internal/object.h
+++ b/internal/object.h
@@ -11,13 +11,10 @@
#include "ruby/ruby.h" /* for VALUE */
/* object.c */
-size_t rb_obj_embedded_size(uint32_t numiv);
VALUE rb_class_search_ancestor(VALUE klass, VALUE super);
NORETURN(void rb_undefined_alloc(VALUE klass));
double rb_num_to_dbl(VALUE val);
VALUE rb_obj_dig(int argc, VALUE *argv, VALUE self, VALUE notfound);
-VALUE rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze);
-VALUE rb_obj_dup_setup(VALUE obj, VALUE dup);
VALUE rb_immutable_obj_clone(int, VALUE *, VALUE);
VALUE rb_check_convert_type_with_id(VALUE,int,const char*,ID);
int rb_bool_expected(VALUE, const char *, int raise);
@@ -30,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);
@@ -38,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 c6a9e38bfa..2416c31e14 100644
--- a/internal/proc.h
+++ b/internal/proc.h
@@ -22,10 +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_proc_dup(VALUE src_obj);
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/random.h b/internal/random.h
index 127b908e16..231e2d5d7e 100644
--- a/internal/random.h
+++ b/internal/random.h
@@ -12,6 +12,5 @@
/* random.c */
int ruby_fill_random_bytes(void *, size_t, int);
-void rb_free_default_rand_key(void);
#endif /* INTERNAL_RANDOM_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 ba2af25877..12edbff2b1 100644
--- a/internal/string.h
+++ b/internal/string.h
@@ -57,7 +57,6 @@ static inline VALUE rb_str_eql_internal(const VALUE str1, const VALUE str2);
RUBY_SYMBOL_EXPORT_BEGIN
/* string.c (export) */
VALUE rb_str_tmp_frozen_acquire(VALUE str);
-VALUE rb_str_tmp_frozen_no_embed_acquire(VALUE str);
void rb_str_tmp_frozen_release(VALUE str, VALUE tmp);
VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc);
VALUE rb_str_upto_each(VALUE, VALUE, int, int (*each)(VALUE, VALUE), VALUE);
@@ -65,8 +64,10 @@ VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE);
void rb_str_make_embedded(VALUE);
size_t rb_str_size_as_embedded(VALUE);
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/symbol.h b/internal/symbol.h
index e7730cb70f..30c81ea004 100644
--- a/internal/symbol.h
+++ b/internal/symbol.h
@@ -32,9 +32,6 @@ ID rb_make_temporary_id(size_t n);
void rb_gc_free_dsymbol(VALUE);
int rb_static_id_valid_p(ID id);
-/* vm.c */
-void rb_free_static_symid_str(void);
-
#if __has_builtin(__builtin_constant_p)
#define rb_sym_intern_ascii_cstr(ptr) \
(__builtin_constant_p(ptr) ? \
diff --git a/internal/thread.h b/internal/thread.h
index 4ed542382b..6394f88d34 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);
@@ -41,7 +29,6 @@ VALUE rb_get_coverages(void);
int rb_get_coverage_mode(void);
VALUE rb_default_coverage(int);
VALUE rb_thread_shield_new(void);
-bool rb_thread_shield_owned(VALUE self);
VALUE rb_thread_shield_wait(VALUE self);
VALUE rb_thread_shield_release(VALUE self);
VALUE rb_thread_shield_destroy(VALUE self);
@@ -50,30 +37,19 @@ 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 closing_fiber;
- 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);
-VALUE rb_thread_io_blocking_call(rb_blocking_function_t *func, void *data1, int fd, int events);
/* thread.c (export) */
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 e21b3574f6..a3bf0587ec 100644
--- a/internal/time.h
+++ b/internal/time.h
@@ -28,10 +28,7 @@ struct timeval rb_time_timeval(VALUE);
RUBY_SYMBOL_EXPORT_BEGIN
/* time.c (export) */
void ruby_reset_leap_second_info(void);
-#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY
-RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
-#endif
-void ruby_reset_timezone(const char *);
+void ruby_reset_timezone(void);
RUBY_SYMBOL_EXPORT_END
#endif /* INTERNAL_TIME_H */
diff --git a/internal/transcode.h b/internal/transcode.h
index ce4f2341be..9922332ea9 100644
--- a/internal/transcode.h
+++ b/internal/transcode.h
@@ -17,7 +17,4 @@
extern VALUE rb_cEncodingConverter;
size_t rb_econv_memsize(rb_econv_t *);
-/* vm.c */
-void rb_free_transcoder_table(void);
-
#endif /* INTERNAL_TRANSCODE_H */
diff --git a/internal/variable.h b/internal/variable.h
index b2a30c7c58..3933279633 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,45 +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);
-void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table);
-void rb_obj_convert_to_too_complex(VALUE obj, st_table *table);
-void rb_evict_ivars_to_hash(VALUE obj);
+int rb_obj_evacuate_ivs_to_hash_table(ID key, VALUE val, st_data_t arg);
RUBY_SYMBOL_EXPORT_BEGIN
/* variable.c (export) */
-void rb_mark_generic_ivar(VALUE obj);
-void rb_ref_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, 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 a32a14e045..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,31 +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
-
-extern bool rb_free_at_exit;
-
-/* miniinit.c and builtin.c */
-void rb_free_loaded_builtin_table(void);
-
/* 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);
@@ -110,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);
@@ -119,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 b4b262b6ac..2e51a46635 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;
@@ -1150,20 +1148,13 @@ io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct time
if (ready > 0) {
return ready;
- }
- else if (ready == 0) {
+ } else if (ready == 0) {
errno = ETIMEDOUT;
return -1;
}
- // If there was an error BEFORE we started waiting, return it:
- if (error) {
- errno = error;
- return -1;
- } else {
- // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
- return ready;
- }
+ errno = error;
+ return -1;
}
static VALUE
@@ -1185,8 +1176,7 @@ internal_read_func(void *ptr)
if (io_again_p(errno)) {
if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
return -1;
- }
- else {
+ } else {
goto retry;
}
}
@@ -1221,8 +1211,7 @@ internal_write_func(void *ptr)
if (io_again_p(e)) {
if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
return -1;
- }
- else {
+ } else {
goto retry;
}
}
@@ -1251,8 +1240,7 @@ internal_writev_func(void *ptr)
if (io_again_p(errno)) {
if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
return -1;
- }
- else {
+ } else {
goto retry;
}
}
@@ -1292,7 +1280,7 @@ rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
iis.timeout = &timeout_storage;
}
- return (ssize_t)rb_thread_io_blocking_call(internal_read_func, &iis, fptr->fd, RB_WAITFD_IN);
+ return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
}
static ssize_t
@@ -1325,22 +1313,21 @@ rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
iis.timeout = &timeout_storage;
}
- return (ssize_t)rb_thread_io_blocking_call(internal_write_func, &iis, fptr->fd, RB_WAITFD_OUT);
+ return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
}
#ifdef HAVE_WRITEV
static ssize_t
rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
{
- if (!iovcnt) return 0;
-
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
- // This path assumes at least one `iov`:
- VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
+ for (int i = 0; i < iovcnt; i += 1) {
+ VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[i].iov_base, iov[i].iov_len, 0);
- if (!UNDEF_P(result)) {
- return rb_fiber_scheduler_io_result_apply(result);
+ if (!UNDEF_P(result)) {
+ return rb_fiber_scheduler_io_result_apply(result);
+ }
}
}
@@ -1362,7 +1349,7 @@ rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
iis.timeout = &timeout_storage;
}
- return (ssize_t)rb_thread_io_blocking_call(internal_writev_func, &iis, fptr->fd, RB_WAITFD_OUT);
+ return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->fd);
}
#endif
@@ -1392,7 +1379,7 @@ static VALUE
io_flush_buffer_async(VALUE arg)
{
rb_io_t *fptr = (rb_io_t *)arg;
- return rb_thread_io_blocking_call(io_flush_buffer_sync, fptr, fptr->fd, RB_WAITFD_OUT);
+ return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
}
static inline int
@@ -1468,7 +1455,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
@@ -1801,11 +1788,13 @@ 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) {
- // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
- // should try again immediately.
+ errno = EWOULDBLOCK;
}
- else if (result > 0) {
+
+ if (result > 0) {
if ((size_t)result == remaining) break;
ptr += result;
remaining -= result;
@@ -1842,7 +1831,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;
@@ -1976,7 +1965,7 @@ io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
if (converted)
OBJ_FREEZE(str);
- tmp = rb_str_tmp_frozen_no_embed_acquire(str);
+ tmp = rb_str_tmp_frozen_acquire(str);
RSTRING_GETMEM(tmp, ptr, len);
n = io_binwrite(tmp, ptr, len, fptr, nosync);
rb_str_tmp_frozen_release(str, tmp);
@@ -2045,7 +2034,7 @@ io_binwritev_internal(VALUE arg)
while (remaining) {
long result = rb_writev_internal(fptr, iov, iovcnt);
- if (result >= 0) {
+ if (result > 0) {
offset += result;
if (fptr->wbuf.ptr && fptr->wbuf.len) {
if (offset < (size_t)fptr->wbuf.len) {
@@ -2395,6 +2384,9 @@ rb_io_flush(VALUE io)
* f.close
*
* Related: IO#pos=, IO#seek.
+ *
+ * IO#pos is an alias for IO#tell.
+ *
*/
static VALUE
@@ -2662,6 +2654,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
@@ -2852,6 +2847,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
@@ -2874,23 +2871,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;
}
/*
@@ -2939,7 +2921,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;
@@ -3280,10 +3262,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;
@@ -3414,12 +3395,7 @@ io_read_memory_call(VALUE arg)
}
}
- if (iis->nonblock) {
- return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, 0);
- }
- else {
- return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->fd, RB_WAITFD_IN);
- }
+ return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
}
static long
@@ -3826,33 +3802,8 @@ 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, rb_encoding *enc)
+appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
{
VALUE str = *strp;
long limit = *lp;
@@ -3867,9 +3818,9 @@ appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
p = READ_CHAR_PENDING_PTR(fptr);
if (0 < limit && limit < searchlen)
searchlen = (int)limit;
- e = search_delim(p, searchlen, delim, enc);
+ e = memchr(p, delim, searchlen);
if (e) {
- int len = (int)(e-p);
+ int len = (int)(e-p+1);
if (NIL_P(str))
*strp = str = rb_str_new(p, len);
else
@@ -3909,8 +3860,8 @@ appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
long last;
if (limit > 0 && pending > limit) pending = limit;
- e = search_delim(p, pending, delim, enc);
- if (e) pending = e - p;
+ e = memchr(p, delim, pending);
+ if (e) pending = e - p + 1;
if (!NIL_P(str)) {
last = RSTRING_LEN(str);
rb_str_resize(str, last + pending);
@@ -4170,26 +4121,16 @@ 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");
}
- chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
+ newline = (unsigned char)rsptr[rslen - 1];
+ chomp_cr = chomp && rslen == 1 && newline == '\n';
}
/* MS - Optimization */
- while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
+ while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
const char *s, *p, *pp, *e;
if (c == newline) {
@@ -4197,7 +4138,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) {
@@ -4210,8 +4152,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_prev_char(s, p, p, enc);
- if (extra_limit && pp &&
+ pp = rb_enc_left_char_head(s, p-1, p, enc);
+ if (extra_limit &&
MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
/* relax the limit while incomplete character.
* extra_limit limits the relax length */
@@ -4409,36 +4351,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)
{
- long limit = -1;
- if (NIL_P(lim)) {
- VALUE tmp = Qnil;
- // 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(tmp = 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;
- limit = NUM2LONG(lim);
- sep = rb_rs;
- }
- else {
- sep = tmp;
- }
- }
- else {
- if (!NIL_P(sep)) StringValue(sep);
- limit = NUM2LONG(lim);
- }
-
- check_getline_args(&sep, &limit, io);
-
- VALUE line = rb_io_getline_1(sep, limit, 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();
@@ -4643,6 +4571,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
@@ -5266,6 +5197,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
@@ -5326,7 +5259,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
@@ -5377,7 +5310,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
@@ -5496,7 +5429,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;
@@ -5527,7 +5460,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;
}
@@ -5539,7 +5472,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.
@@ -5641,9 +5574,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);
@@ -5651,14 +5587,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
@@ -5694,14 +5623,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;
@@ -5838,8 +5769,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;
@@ -6137,37 +6070,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_call(internal_pread_func, arg, arg->fd, RB_WAITFD_IN);
+ struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
+ return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
}
/*
@@ -6204,7 +6128,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);
@@ -6234,21 +6158,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);
}
@@ -6283,7 +6201,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))
@@ -6300,12 +6218,15 @@ rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
arg.buf = RSTRING_PTR(tmp);
arg.count = (size_t)RSTRING_LEN(tmp);
- n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->fd, RB_WAITFD_OUT);
+ n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
if (n < 0) rb_sys_fail_path(fptr->pathv);
rb_str_tmp_frozen_release(str, tmp);
return SSIZET2NUM(n);
}
+#else
+# define rb_io_pwrite rb_f_notimplement
+#endif /* HAVE_PWRITE */
VALUE
rb_io_binmode(VALUE io)
@@ -6790,6 +6711,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)
{
@@ -6848,7 +6771,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;
@@ -7019,7 +6942,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);
@@ -7027,14 +6950,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;
@@ -7043,22 +6973,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. */
@@ -7165,11 +7099,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);
@@ -7203,7 +7137,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(),
@@ -7311,7 +7245,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
@@ -7349,7 +7283,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]);
@@ -7511,7 +7450,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 ;
@@ -7740,7 +7679,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");
}
@@ -7762,7 +7701,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;
@@ -7971,7 +7910,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)) {
@@ -8008,7 +7947,7 @@ popen_finish(VALUE port, VALUE klass)
if (NIL_P(port)) {
/* child */
if (rb_block_given_p()) {
- rb_protect(rb_yield, Qnil, NULL);
+ rb_yield(Qnil);
rb_io_flush(rb_ractor_stdout());
rb_io_flush(rb_ractor_stderr());
_exit(0);
@@ -8022,64 +7961,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;
@@ -8103,7 +7988,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);
@@ -8119,11 +8004,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.
*
*/
@@ -8221,10 +8106,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:
*
@@ -8241,6 +8136,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
@@ -8263,8 +8219,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);
}
@@ -8282,13 +8236,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);
@@ -8298,12 +8252,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 {
@@ -8324,7 +8276,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))) {
@@ -8350,17 +8302,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);
@@ -8465,10 +8417,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,
@@ -8547,7 +8499,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;
@@ -8911,9 +8863,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:
*
@@ -8946,6 +8898,7 @@ io_puts_ary(VALUE ary, VALUE out, int recur)
VALUE
rb_io_puts(int argc, const VALUE *argv, VALUE out)
{
+ int i, n;
VALUE line, args[2];
/* if no argument given, print newline. */
@@ -8953,30 +8906,22 @@ rb_io_puts(int argc, const VALUE *argv, VALUE out)
rb_io_write(out, rb_default_rs);
return Qnil;
}
- for (int i = 0; i < argc; i++) {
- // Convert the argument to a string:
+ for (i=0; i<argc; i++) {
if (RB_TYPE_P(argv[i], T_STRING)) {
line = argv[i];
+ goto string;
}
- else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
+ if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
continue;
}
- else {
- line = rb_obj_as_string(argv[i]);
- }
-
- // Write the line:
- int n = 0;
- if (RSTRING_LEN(line) == 0) {
+ line = rb_obj_as_string(argv[i]);
+ string:
+ n = 0;
+ args[n++] = line;
+ if (RSTRING_LEN(line) == 0 ||
+ !rb_str_end_with_asciichar(line, '\n')) {
args[n++] = rb_default_rs;
}
- else {
- args[n++] = line;
- if (!rb_str_end_with_asciichar(line, '\n')) {
- args[n++] = rb_default_rs;
- }
- }
-
rb_io_writev(out, n, args);
}
@@ -9069,10 +9014,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
@@ -9226,78 +9167,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
@@ -9313,7 +9202,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;
@@ -9357,7 +9246,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;
@@ -9460,7 +9349,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;
@@ -9497,7 +9386,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));
@@ -9576,9 +9465,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=.
*
@@ -9666,7 +9555,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
@@ -9674,7 +9563,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));
}
/*
@@ -9683,14 +9572,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
*/
@@ -9700,9 +9589,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;
}
@@ -9835,7 +9724,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);
@@ -9866,7 +9755,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.
@@ -10520,21 +10409,19 @@ rb_f_readlines(int argc, VALUE *argv, VALUE recv)
/*
* call-seq:
- * ARGF.readlines(sep = $/, chomp: false) -> array
- * ARGF.readlines(limit, chomp: false) -> array
- * ARGF.readlines(sep, limit, chomp: false) -> array
+ * ARGF.readlines(sep = $/) -> array
+ * ARGF.readlines(limit) -> array
+ * ARGF.readlines(sep, limit) -> array
*
- * ARGF.to_a(sep = $/, chomp: false) -> array
- * ARGF.to_a(limit, chomp: false) -> array
- * ARGF.to_a(sep, limit, chomp: false) -> array
+ * ARGF.to_a(sep = $/) -> array
+ * ARGF.to_a(limit) -> array
+ * ARGF.to_a(sep, limit) -> array
*
* Reads each file in ARGF in its entirety, returning an Array containing
* lines from the files. Lines are assumed to be separated by _sep_.
*
* lines = ARGF.readlines
* lines[0] #=> "This is line one\n"
- *
- * See +IO.readlines+ for a full description of all options.
*/
static VALUE
argf_readlines(int argc, VALUE *argv, VALUE argf)
@@ -10596,7 +10483,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;
@@ -11497,7 +11385,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.)
*
@@ -11685,11 +11573,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);
}
@@ -11750,9 +11633,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.
@@ -11963,6 +11846,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.
@@ -11971,7 +11857,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,
@@ -12032,7 +11927,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.
*
@@ -12065,6 +11960,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
@@ -12075,7 +11973,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,
@@ -12084,6 +11994,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]):
*
@@ -12113,7 +12025,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].
*
*/
@@ -12156,6 +12068,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,
@@ -12165,7 +12078,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:
@@ -12177,6 +12101,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"
@@ -12200,13 +12126,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)) {
@@ -12227,6 +12149,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
@@ -12250,7 +12173,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]);
@@ -12331,6 +12254,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,
@@ -12340,9 +12264,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"
@@ -12381,6 +12321,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
@@ -12937,7 +12878,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;
@@ -13104,7 +13050,6 @@ 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;
}
@@ -13448,12 +13393,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
@@ -13461,10 +13404,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].
*
@@ -14472,7 +14411,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);
}
/*
@@ -14751,16 +14690,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"
*/
/*
@@ -14778,7 +14712,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:
*
@@ -14796,7 +14730,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].
@@ -14832,7 +14766,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.
@@ -14847,7 +14781,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
*
@@ -15122,7 +15056,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')
@@ -15371,14 +15305,10 @@ 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);
- /* Readable event mask for IO#wait. */
rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
- /* Writable event mask for IO#wait. */
rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
- /* Priority event mask for IO#wait. */
rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
/* exception to wait for reading. see IO.select. */
@@ -15492,6 +15422,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);
@@ -15526,7 +15457,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);
@@ -15570,13 +15501,14 @@ Init_IO(void)
rb_gvar_ractor_local("$>");
rb_gvar_ractor_local("$stderr");
- rb_global_variable(&rb_stdin);
rb_stdin = rb_io_prep_stdin();
- rb_global_variable(&rb_stdout);
rb_stdout = rb_io_prep_stdout();
- rb_global_variable(&rb_stderr);
rb_stderr = rb_io_prep_stderr();
+ rb_global_variable(&rb_stdin);
+ rb_global_variable(&rb_stdout);
+ rb_global_variable(&rb_stderr);
+
orig_stdout = rb_stdout;
orig_stderr = rb_stderr;
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 ea46b149f6..c5f0b193c3 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -34,18 +34,6 @@ size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
#include <sys/mman.h>
#endif
-enum {
- RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH = 16,
-
- RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE = 256,
- RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH = 16,
-
- // This is used to validate the flags given by the user.
- RB_IO_BUFFER_FLAGS_MASK = RB_IO_BUFFER_EXTERNAL | RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED | RB_IO_BUFFER_SHARED | RB_IO_BUFFER_LOCKED | RB_IO_BUFFER_PRIVATE | RB_IO_BUFFER_READONLY,
-
- RB_IO_BUFFER_DEBUG = 0,
-};
-
struct rb_io_buffer {
void *base;
size_t size;
@@ -71,8 +59,7 @@ io_buffer_map_memory(size_t size, int flags)
int mmap_flags = MAP_ANONYMOUS;
if (flags & RB_IO_BUFFER_SHARED) {
mmap_flags |= MAP_SHARED;
- }
- else {
+ } else {
mmap_flags |= MAP_PRIVATE;
}
@@ -87,7 +74,7 @@ io_buffer_map_memory(size_t size, int flags)
}
static void
-io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_off_t offset, enum rb_io_buffer_flags flags)
+io_buffer_map_file(struct rb_io_buffer *data, int descriptor, size_t size, rb_off_t offset, enum rb_io_buffer_flags flags)
{
#if defined(_WIN32)
HANDLE file = (HANDLE)_get_osfhandle(descriptor);
@@ -96,28 +83,26 @@ io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_
DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
if (flags & RB_IO_BUFFER_READONLY) {
- buffer->flags |= RB_IO_BUFFER_READONLY;
+ data->flags |= RB_IO_BUFFER_READONLY;
}
else {
protect = PAGE_READWRITE;
access = FILE_MAP_WRITE;
}
+ HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
+ if (!mapping) rb_sys_fail("io_buffer_map_descriptor:CreateFileMapping");
+
if (flags & RB_IO_BUFFER_PRIVATE) {
- protect = PAGE_WRITECOPY;
- access = FILE_MAP_COPY;
- buffer->flags |= RB_IO_BUFFER_PRIVATE;
+ access |= FILE_MAP_COPY;
+ data->flags |= RB_IO_BUFFER_PRIVATE;
}
else {
- // This buffer refers to external buffer.
- buffer->flags |= RB_IO_BUFFER_EXTERNAL;
- buffer->flags |= RB_IO_BUFFER_SHARED;
+ // This buffer refers to external data.
+ data->flags |= RB_IO_BUFFER_EXTERNAL;
+ data->flags |= RB_IO_BUFFER_SHARED;
}
- HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
- if (RB_IO_BUFFER_DEBUG) fprintf(stderr, "io_buffer_map_file:CreateFileMapping -> %p\n", mapping);
- if (!mapping) rb_sys_fail("io_buffer_map_descriptor:CreateFileMapping");
-
void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size);
if (!base) {
@@ -125,25 +110,24 @@ io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_
rb_sys_fail("io_buffer_map_file:MapViewOfFile");
}
- buffer->mapping = mapping;
+ data->mapping = mapping;
#else
int protect = PROT_READ, access = 0;
if (flags & RB_IO_BUFFER_READONLY) {
- buffer->flags |= RB_IO_BUFFER_READONLY;
+ data->flags |= RB_IO_BUFFER_READONLY;
}
else {
protect |= PROT_WRITE;
}
if (flags & RB_IO_BUFFER_PRIVATE) {
- buffer->flags |= RB_IO_BUFFER_PRIVATE;
- access |= MAP_PRIVATE;
+ data->flags |= RB_IO_BUFFER_PRIVATE;
}
else {
- // This buffer refers to external buffer.
- buffer->flags |= RB_IO_BUFFER_EXTERNAL;
- buffer->flags |= RB_IO_BUFFER_SHARED;
+ // This buffer refers to external data.
+ data->flags |= RB_IO_BUFFER_EXTERNAL;
+ data->flags |= RB_IO_BUFFER_SHARED;
access |= MAP_SHARED;
}
@@ -154,11 +138,20 @@ io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_
}
#endif
- buffer->base = base;
- buffer->size = size;
+ data->base = base;
+ data->size = size;
- buffer->flags |= RB_IO_BUFFER_MAPPED;
- buffer->flags |= RB_IO_BUFFER_FILE;
+ data->flags |= RB_IO_BUFFER_MAPPED;
+}
+
+static inline void
+io_buffer_unmap(void* base, size_t size)
+{
+#ifdef _WIN32
+ VirtualFree(base, 0, MEM_RELEASE);
+#else
+ munmap(base, size);
+#endif
}
static void
@@ -178,18 +171,18 @@ io_buffer_experimental(void)
}
static void
-io_buffer_zero(struct rb_io_buffer *buffer)
+io_buffer_zero(struct rb_io_buffer *data)
{
- buffer->base = NULL;
- buffer->size = 0;
+ data->base = NULL;
+ data->size = 0;
#if defined(_WIN32)
- buffer->mapping = NULL;
+ data->mapping = NULL;
#endif
- buffer->source = Qnil;
+ data->source = Qnil;
}
static void
-io_buffer_initialize(VALUE self, struct rb_io_buffer *buffer, void *base, size_t size, enum rb_io_buffer_flags flags, VALUE source)
+io_buffer_initialize(struct rb_io_buffer *data, void *base, size_t size, enum rb_io_buffer_flags flags, VALUE source)
{
if (base) {
// If we are provided a pointer, we use it.
@@ -212,84 +205,73 @@ io_buffer_initialize(VALUE self, struct rb_io_buffer *buffer, void *base, size_t
return;
}
- buffer->base = base;
- buffer->size = size;
- buffer->flags = flags;
- RB_OBJ_WRITE(self, &buffer->source, source);
-
-#if defined(_WIN32)
- buffer->mapping = NULL;
-#endif
+ data->base = base;
+ data->size = size;
+ data->flags = flags;
+ data->source = source;
}
-static void
-io_buffer_free(struct rb_io_buffer *buffer)
+static int
+io_buffer_free(struct rb_io_buffer *data)
{
- if (buffer->base) {
- if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
- free(buffer->base);
+ if (data->base) {
+ if (data->flags & RB_IO_BUFFER_INTERNAL) {
+ free(data->base);
}
- if (buffer->flags & RB_IO_BUFFER_MAPPED) {
-#ifdef _WIN32
- if (buffer->flags & RB_IO_BUFFER_FILE) {
- UnmapViewOfFile(buffer->base);
- }
- else {
- VirtualFree(buffer->base, 0, MEM_RELEASE);
- }
-#else
- munmap(buffer->base, buffer->size);
-#endif
+ if (data->flags & RB_IO_BUFFER_MAPPED) {
+ io_buffer_unmap(data->base, data->size);
}
// Previously we had this, but we found out due to the way GC works, we
// can't refer to any other Ruby objects here.
- // if (RB_TYPE_P(buffer->source, T_STRING)) {
- // rb_str_unlocktmp(buffer->source);
+ // if (RB_TYPE_P(data->source, T_STRING)) {
+ // rb_str_unlocktmp(data->source);
// }
- buffer->base = NULL;
-
- buffer->size = 0;
- buffer->flags = 0;
- buffer->source = Qnil;
- }
+ data->base = NULL;
#if defined(_WIN32)
- if (buffer->mapping) {
- if (RB_IO_BUFFER_DEBUG) fprintf(stderr, "io_buffer_free:CloseHandle -> %p\n", buffer->mapping);
- if (!CloseHandle(buffer->mapping)) {
- fprintf(stderr, "io_buffer_free:GetLastError -> %d\n", GetLastError());
+ if (data->mapping) {
+ CloseHandle(data->mapping);
+ data->mapping = NULL;
}
- buffer->mapping = NULL;
- }
#endif
+ data->size = 0;
+ data->flags = 0;
+ data->source = Qnil;
+
+ return 1;
+ }
+
+ return 0;
}
void
-rb_io_buffer_type_mark(void *_buffer)
+rb_io_buffer_type_mark(void *_data)
{
- struct rb_io_buffer *buffer = _buffer;
- rb_gc_mark(buffer->source);
+ struct rb_io_buffer *data = _data;
+ rb_gc_mark(data->source);
}
void
-rb_io_buffer_type_free(void *_buffer)
+rb_io_buffer_type_free(void *_data)
{
- struct rb_io_buffer *buffer = _buffer;
+ struct rb_io_buffer *data = _data;
+
+ io_buffer_free(data);
- io_buffer_free(buffer);
+ free(data);
}
size_t
-rb_io_buffer_type_size(const void *_buffer)
+rb_io_buffer_type_size(const void *_data)
{
- const struct rb_io_buffer *buffer = _buffer;
+ const struct rb_io_buffer *data = _data;
size_t total = sizeof(struct rb_io_buffer);
- if (buffer->flags) {
- total += buffer->size;
+ if (data->flags) {
+ total += data->size;
}
return total;
@@ -303,178 +285,34 @@ static const rb_data_type_t rb_io_buffer_type = {
.dsize = rb_io_buffer_type_size,
},
.data = NULL,
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
};
-static inline enum rb_io_buffer_flags
-io_buffer_extract_flags(VALUE argument)
-{
- if (rb_int_negative_p(argument)) {
- rb_raise(rb_eArgError, "Flags can't be negative!");
- }
-
- enum rb_io_buffer_flags flags = RB_NUM2UINT(argument);
-
- // We deliberately ignore unknown flags. Any future flags which are exposed this way should be safe to ignore.
- return flags & RB_IO_BUFFER_FLAGS_MASK;
-}
-
-// Extract an offset argument, which must be a non-negative integer.
-static inline size_t
-io_buffer_extract_offset(VALUE argument)
-{
- if (rb_int_negative_p(argument)) {
- rb_raise(rb_eArgError, "Offset can't be negative!");
- }
-
- return NUM2SIZET(argument);
-}
-
-// Extract a length argument, which must be a non-negative integer.
-// Length is generally considered a mutable property of an object and
-// semantically should be considered a subset of "size" as a concept.
-static inline size_t
-io_buffer_extract_length(VALUE argument)
-{
- if (rb_int_negative_p(argument)) {
- rb_raise(rb_eArgError, "Length can't be negative!");
- }
-
- return NUM2SIZET(argument);
-}
-
-// Extract a size argument, which must be a non-negative integer.
-// Size is generally considered an immutable property of an object.
-static inline size_t
-io_buffer_extract_size(VALUE argument)
-{
- if (rb_int_negative_p(argument)) {
- rb_raise(rb_eArgError, "Size can't be negative!");
- }
-
- return NUM2SIZET(argument);
-}
-
-// Extract a width argument, which must be a non-negative integer, and must be
-// at least the given minimum.
-static inline size_t
-io_buffer_extract_width(VALUE argument, size_t minimum)
-{
- if (rb_int_negative_p(argument)) {
- rb_raise(rb_eArgError, "Width can't be negative!");
- }
-
- size_t width = NUM2SIZET(argument);
-
- if (width < minimum) {
- rb_raise(rb_eArgError, "Width must be at least %" PRIuSIZE "!", minimum);
- }
-
- return width;
-}
-
-// Compute the default length for a buffer, given an offset into that buffer.
-// The default length is the size of the buffer minus the offset. The offset
-// must be less than the size of the buffer otherwise the length will be
-// invalid; in that case, an ArgumentError exception will be raised.
-static inline size_t
-io_buffer_default_length(const struct rb_io_buffer *buffer, size_t offset)
-{
- if (offset > buffer->size) {
- rb_raise(rb_eArgError, "The given offset is bigger than the buffer size!");
- }
-
- // Note that the "length" is computed by the size the offset.
- return buffer->size - offset;
-}
-
-// Extract the optional length and offset arguments, returning the buffer.
-// The length and offset are optional, but if they are provided, they must be
-// positive integers. If the length is not provided, the default length is
-// computed from the buffer size and offset. If the offset is not provided, it
-// defaults to zero.
-static inline struct rb_io_buffer *
-io_buffer_extract_length_offset(VALUE self, int argc, VALUE argv[], size_t *length, size_t *offset)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- if (argc >= 2 && !NIL_P(argv[1])) {
- *offset = io_buffer_extract_offset(argv[1]);
- }
- else {
- *offset = 0;
- }
-
- if (argc >= 1 && !NIL_P(argv[0])) {
- *length = io_buffer_extract_length(argv[0]);
- }
- else {
- *length = io_buffer_default_length(buffer, *offset);
- }
-
- return buffer;
-}
-
-// Extract the optional offset and length arguments, returning the buffer.
-// Similar to `io_buffer_extract_length_offset` but with the order of arguments
-// reversed.
-//
-// After much consideration, I decided to accept both forms.
-// The `(offset, length)` order is more natural when referring about data,
-// while the `(length, offset)` order is more natural when referring to
-// read/write operations. In many cases, with the latter form, `offset`
-// is usually not supplied.
-static inline struct rb_io_buffer *
-io_buffer_extract_offset_length(VALUE self, int argc, VALUE argv[], size_t *offset, size_t *length)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- if (argc >= 1 && !NIL_P(argv[0])) {
- *offset = io_buffer_extract_offset(argv[0]);
- }
- else {
- *offset = 0;
- }
-
- if (argc >= 2 && !NIL_P(argv[1])) {
- *length = io_buffer_extract_length(argv[1]);
- }
- else {
- *length = io_buffer_default_length(buffer, *offset);
- }
-
- return buffer;
-}
-
VALUE
rb_io_buffer_type_allocate(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- VALUE instance = TypedData_Make_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ VALUE instance = TypedData_Make_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- io_buffer_zero(buffer);
+ io_buffer_zero(data);
return instance;
}
-static VALUE io_buffer_for_make_instance(VALUE klass, VALUE string, enum rb_io_buffer_flags flags)
+static VALUE
+io_buffer_for_make_instance(VALUE klass, VALUE string)
{
VALUE instance = rb_io_buffer_type_allocate(klass);
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, data);
- flags |= RB_IO_BUFFER_EXTERNAL;
+ enum rb_io_buffer_flags flags = RB_IO_BUFFER_EXTERNAL;
if (RB_OBJ_FROZEN(string))
flags |= RB_IO_BUFFER_READONLY;
- if (!(flags & RB_IO_BUFFER_READONLY))
- rb_str_modify(string);
-
- io_buffer_initialize(instance, buffer, RSTRING_PTR(string), RSTRING_LEN(string), flags, string);
+ io_buffer_initialize(data, RSTRING_PTR(string), RSTRING_LEN(string), flags, string);
return instance;
}
@@ -483,7 +321,6 @@ struct io_buffer_for_yield_instance_arguments {
VALUE klass;
VALUE string;
VALUE instance;
- enum rb_io_buffer_flags flags;
};
static VALUE
@@ -491,10 +328,10 @@ io_buffer_for_yield_instance(VALUE _arguments)
{
struct io_buffer_for_yield_instance_arguments *arguments = (struct io_buffer_for_yield_instance_arguments *)_arguments;
- arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
-
rb_str_locktmp(arguments->string);
+ arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string);
+
return rb_yield(arguments->instance);
}
@@ -517,18 +354,17 @@ io_buffer_for_yield_instance_ensure(VALUE _arguments)
* IO::Buffer.for(string) -> readonly io_buffer
* IO::Buffer.for(string) {|io_buffer| ... read/write io_buffer ...}
*
- * Creates a zero-copy IO::Buffer from the given string's memory. Without a
- * block a frozen internal copy of the string is created efficiently and used
- * as the buffer source. When a block is provided, the buffer is associated
- * directly with the string's internal buffer and updating the buffer will
- * update the string.
+ * Creates a IO::Buffer from the given string's memory. Without a block a
+ * frozen internal copy of the string is created efficiently and used as the
+ * buffer source. When a block is provided, the buffer is associated directly
+ * with the string's internal data and updating the buffer will update the
+ * string.
*
* Until #free is invoked on the buffer, either explicitly or via the garbage
* collector, the source string will be locked and cannot be modified.
*
* If the string is frozen, it will create a read-only buffer which cannot be
- * modified. If the string is shared, it may trigger a copy-on-write when
- * using the block form.
+ * modified.
*
* string = 'test'
* buffer = IO::Buffer.for(string)
@@ -560,7 +396,6 @@ rb_io_buffer_type_for(VALUE klass, VALUE string)
.klass = klass,
.string = string,
.instance = Qnil,
- .flags = 0,
};
return rb_ensure(io_buffer_for_yield_instance, (VALUE)&arguments, io_buffer_for_yield_instance_ensure, (VALUE)&arguments);
@@ -568,48 +403,19 @@ rb_io_buffer_type_for(VALUE klass, VALUE string)
else {
// This internally returns the source string if it's already frozen.
string = rb_str_tmp_frozen_acquire(string);
- return io_buffer_for_make_instance(klass, string, RB_IO_BUFFER_READONLY);
+ return io_buffer_for_make_instance(klass, 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 zero-copy 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)
{
VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, data);
- io_buffer_initialize(instance, buffer, base, size, flags, Qnil);
+ io_buffer_initialize(data, base, size, flags, Qnil);
return instance;
}
@@ -621,12 +427,12 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags
VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, data);
int descriptor = rb_io_descriptor(io);
- io_buffer_map_file(buffer, descriptor, size, offset, flags);
+ io_buffer_map_file(data, descriptor, size, offset, flags);
return instance;
}
@@ -643,6 +449,8 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags
* mapping, you need to open a file in read-write mode, and explicitly pass
* +flags+ argument without IO::Buffer::IMMUTABLE.
*
+ * Example:
+ *
* File.write('test.txt', 'test')
*
* buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
@@ -678,7 +486,7 @@ io_buffer_map(int argc, VALUE *argv, VALUE klass)
size_t size;
if (argc >= 2 && !RB_NIL_P(argv[1])) {
- size = io_buffer_extract_size(argv[1]);
+ size = RB_NUM2SIZE(argv[1]);
}
else {
rb_off_t file_size = rb_file_size(io);
@@ -697,7 +505,6 @@ io_buffer_map(int argc, VALUE *argv, VALUE klass)
}
}
- // This is the file offset, not the buffer offset:
rb_off_t offset = 0;
if (argc >= 3) {
offset = NUM2OFFT(argv[2]);
@@ -705,7 +512,7 @@ io_buffer_map(int argc, VALUE *argv, VALUE klass)
enum rb_io_buffer_flags flags = 0;
if (argc >= 4) {
- flags = io_buffer_extract_flags(argv[3]);
+ flags = RB_NUM2UINT(argv[3]);
}
return rb_io_buffer_map(io, size, offset, flags);
@@ -733,6 +540,8 @@ io_flags_for_size(size_t size)
* on Windows). The behavior can be forced by passing IO::Buffer::MAPPED
* as a second parameter.
*
+ * Examples
+ *
* buffer = IO::Buffer.new(4)
* # =>
* # #<IO::Buffer 0x000055b34497ea10+4 INTERNAL>
@@ -753,12 +562,13 @@ rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self)
rb_check_arity(argc, 0, 2);
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
size_t size;
+
if (argc > 0) {
- size = io_buffer_extract_size(argv[0]);
+ size = RB_NUM2SIZE(argv[0]);
}
else {
size = RUBY_IO_BUFFER_DEFAULT_SIZE;
@@ -766,13 +576,13 @@ rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self)
enum rb_io_buffer_flags flags = 0;
if (argc >= 2) {
- flags = io_buffer_extract_flags(argv[1]);
+ flags = RB_NUM2UINT(argv[1]);
}
else {
flags |= io_flags_for_size(size);
}
- io_buffer_initialize(self, buffer, NULL, size, flags, Qnil);
+ io_buffer_initialize(data, NULL, size, flags, Qnil);
return self;
}
@@ -807,94 +617,17 @@ io_buffer_validate_slice(VALUE source, void *base, size_t size)
}
static int
-io_buffer_validate(struct rb_io_buffer *buffer)
+io_buffer_validate(struct rb_io_buffer *data)
{
- if (buffer->source != Qnil) {
+ if (data->source != Qnil) {
// Only slices incur this overhead, unfortunately... better safe than sorry!
- return io_buffer_validate_slice(buffer->source, buffer->base, buffer->size);
+ return io_buffer_validate_slice(data->source, data->base, data->size);
}
else {
return 1;
}
}
-enum rb_io_buffer_flags
-rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- if (io_buffer_validate(buffer)) {
- if (buffer->base) {
- *base = buffer->base;
- *size = buffer->size;
-
- return buffer->flags;
- }
- }
-
- *base = NULL;
- *size = 0;
-
- return 0;
-}
-
-// Internal function for accessing bytes for writing, wil
-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 ||
- (!NIL_P(buffer->source) && OBJ_FROZEN(buffer->source))) {
- rb_raise(rb_eIOBufferAccessError, "Buffer is not writable!");
- }
-
- if (!io_buffer_validate(buffer)) {
- rb_raise(rb_eIOBufferInvalidatedError, "Buffer is invalid!");
- }
-
- if (buffer->base) {
- *base = buffer->base;
- *size = buffer->size;
- } else {
- *base = NULL;
- *size = 0;
- }
-}
-
-void
-rb_io_buffer_get_bytes_for_writing(VALUE self, void **base, size_t *size)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- io_buffer_get_bytes_for_writing(buffer, base, size);
-}
-
-static void
-io_buffer_get_bytes_for_reading(struct rb_io_buffer *buffer, const void **base, size_t *size)
-{
- if (!io_buffer_validate(buffer)) {
- rb_raise(rb_eIOBufferInvalidatedError, "Buffer has been invalidated!");
- }
-
- if (buffer->base) {
- *base = buffer->base;
- *size = buffer->size;
- } else {
- *base = NULL;
- *size = 0;
- }
-}
-
-void
-rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- io_buffer_get_bytes_for_reading(buffer, base, size);
-}
-
/*
* call-seq: to_s -> string
*
@@ -907,93 +640,60 @@ rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size)
VALUE
rb_io_buffer_to_s(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
VALUE result = rb_str_new_cstr("#<");
rb_str_append(result, rb_class_name(CLASS_OF(self)));
- rb_str_catf(result, " %p+%"PRIdSIZE, buffer->base, buffer->size);
+ rb_str_catf(result, " %p+%"PRIdSIZE, data->base, data->size);
- if (buffer->base == NULL) {
+ if (data->base == NULL) {
rb_str_cat2(result, " NULL");
}
- if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
+ if (data->flags & RB_IO_BUFFER_EXTERNAL) {
rb_str_cat2(result, " EXTERNAL");
}
- if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
+ if (data->flags & RB_IO_BUFFER_INTERNAL) {
rb_str_cat2(result, " INTERNAL");
}
- if (buffer->flags & RB_IO_BUFFER_MAPPED) {
+ if (data->flags & RB_IO_BUFFER_MAPPED) {
rb_str_cat2(result, " MAPPED");
}
- if (buffer->flags & RB_IO_BUFFER_FILE) {
- rb_str_cat2(result, " FILE");
- }
-
- if (buffer->flags & RB_IO_BUFFER_SHARED) {
+ if (data->flags & RB_IO_BUFFER_SHARED) {
rb_str_cat2(result, " SHARED");
}
- if (buffer->flags & RB_IO_BUFFER_LOCKED) {
+ if (data->flags & RB_IO_BUFFER_LOCKED) {
rb_str_cat2(result, " LOCKED");
}
- if (buffer->flags & RB_IO_BUFFER_PRIVATE) {
- rb_str_cat2(result, " PRIVATE");
- }
-
- if (buffer->flags & RB_IO_BUFFER_READONLY) {
+ if (data->flags & RB_IO_BUFFER_READONLY) {
rb_str_cat2(result, " READONLY");
}
- if (buffer->source != Qnil) {
+ if (data->source != Qnil) {
rb_str_cat2(result, " SLICE");
}
- if (!io_buffer_validate(buffer)) {
+ if (!io_buffer_validate(data)) {
rb_str_cat2(result, " INVALID");
}
return rb_str_cat2(result, ">");
}
-// Compute the output size of a hexdump of the given width (bytes per line), total size, and whether it is the first line in the output.
-// This is used to preallocate the output string.
-inline static size_t
-io_buffer_hexdump_output_size(size_t width, size_t size, int first)
-{
- // The preview on the right hand side is 1:1:
- size_t total = size;
-
- size_t whole_lines = (size / width);
- size_t partial_line = (size % width) ? 1 : 0;
-
- // For each line:
- // 1 byte 10 bytes 1 byte width*3 bytes 1 byte size bytes
- // (newline) (address) (space) (hexdump ) (space) (preview)
- total += (whole_lines + partial_line) * (1 + 10 + width*3 + 1 + 1);
-
- // If the hexdump is the first line, one less newline will be emitted:
- if (size && first) total -= 1;
-
- return total;
-}
-
-// Append a hexdump of the given width (bytes per line), base address, size, and whether it is the first line in the output.
-// If the hexdump is not the first line, it will prepend a newline if there is any output at all.
-// If formatting here is adjusted, please update io_buffer_hexdump_output_size accordingly.
static VALUE
-io_buffer_hexdump(VALUE string, size_t width, const char *base, size_t length, size_t offset, int first)
+io_buffer_hexdump(VALUE string, size_t width, char *base, size_t size, int first)
{
char *text = alloca(width+1);
text[width] = '\0';
- for (; offset < length; offset += width) {
+ for (size_t offset = 0; offset < size; offset += width) {
memset(text, '\0', width);
if (first) {
rb_str_catf(string, "0x%08" PRIxSIZE " ", offset);
@@ -1004,7 +704,7 @@ io_buffer_hexdump(VALUE string, size_t width, const char *base, size_t length, s
}
for (size_t i = 0; i < width; i += 1) {
- if (offset+i < length) {
+ if (offset+i < size) {
unsigned char value = ((unsigned char*)base)[offset+i];
if (value < 127 && isprint(value)) {
@@ -1027,40 +727,35 @@ io_buffer_hexdump(VALUE string, size_t width, const char *base, size_t length, s
return string;
}
-/*
- * call-seq: inspect -> string
- *
- * Inspect the buffer and report useful information about it's internal state.
- * Only a limited portion of the buffer will be displayed in a hexdump style
- * format.
- *
- * buffer = IO::Buffer.for("Hello World")
- * puts buffer.inspect
- * # #<IO::Buffer 0x000000010198ccd8+11 EXTERNAL READONLY SLICE>
- * # 0x00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 Hello World
- */
-VALUE
-rb_io_buffer_inspect(VALUE self)
+static VALUE
+rb_io_buffer_hexdump(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- VALUE result = rb_io_buffer_to_s(self);
+ VALUE result = Qnil;
- if (io_buffer_validate(buffer)) {
- // Limit the maximum size generated by inspect:
- size_t size = buffer->size;
- int clamped = 0;
+ if (io_buffer_validate(data) && data->base) {
+ result = rb_str_buf_new(data->size*3 + (data->size/16)*12 + 1);
- if (size > RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE) {
- size = RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE;
- clamped = 1;
- }
+ io_buffer_hexdump(result, 16, data->base, data->size, 1);
+ }
- io_buffer_hexdump(result, RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH, buffer->base, size, 0, 0);
+ return result;
+}
+
+VALUE
+rb_io_buffer_inspect(VALUE self)
+{
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- if (clamped) {
- rb_str_catf(result, "\n(and %" PRIuSIZE " more bytes not printed)", buffer->size - size);
+ VALUE result = rb_io_buffer_to_s(self);
+
+ if (io_buffer_validate(data)) {
+ // Limit the maximum size genearted by inspect.
+ if (data->size <= 256) {
+ io_buffer_hexdump(result, 16, data->base, data->size, 0);
}
}
@@ -1076,50 +771,42 @@ rb_io_buffer_inspect(VALUE self)
VALUE
rb_io_buffer_size(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return SIZET2NUM(buffer->size);
+ return SIZET2NUM(data->size);
}
/*
* call-seq: valid? -> true or false
*
- * Returns whether the buffer buffer is accessible.
+ * Returns whether the buffer data is accessible.
*
- * A buffer becomes invalid if it is a slice of another buffer (or string)
- * which has been freed or re-allocated at a different address.
+ * A buffer becomes invalid if it is a slice of another buffer which has been
+ * freed.
*/
static VALUE
rb_io_buffer_valid_p(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return RBOOL(io_buffer_validate(buffer));
+ return RBOOL(io_buffer_validate(data));
}
/*
* call-seq: null? -> true or false
*
- * If the buffer was freed with #free, transferred with #transfer, or was
- * never allocated in the first place.
- *
- * buffer = IO::Buffer.new(0)
- * buffer.null? #=> true
- *
- * buffer = IO::Buffer.new(4)
- * buffer.null? #=> false
- * buffer.free
- * buffer.null? #=> true
+ * If the buffer was freed with #free or was never allocated in the first
+ * place.
*/
static VALUE
rb_io_buffer_null_p(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return RBOOL(buffer->base == NULL);
+ return RBOOL(data->base == NULL);
}
/*
@@ -1132,10 +819,10 @@ rb_io_buffer_null_p(VALUE self)
static VALUE
rb_io_buffer_empty_p(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return RBOOL(buffer->size == 0);
+ return RBOOL(data->size == 0);
}
/*
@@ -1152,10 +839,10 @@ rb_io_buffer_empty_p(VALUE self)
static VALUE
rb_io_buffer_external_p(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return RBOOL(buffer->flags & RB_IO_BUFFER_EXTERNAL);
+ return RBOOL(data->flags & RB_IO_BUFFER_EXTERNAL);
}
/*
@@ -1177,10 +864,10 @@ rb_io_buffer_external_p(VALUE self)
static VALUE
rb_io_buffer_internal_p(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return RBOOL(buffer->flags & RB_IO_BUFFER_INTERNAL);
+ return RBOOL(data->flags & RB_IO_BUFFER_INTERNAL);
}
/*
@@ -1199,10 +886,10 @@ rb_io_buffer_internal_p(VALUE self)
static VALUE
rb_io_buffer_mapped_p(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return RBOOL(buffer->flags & RB_IO_BUFFER_MAPPED);
+ return RBOOL(data->flags & RB_IO_BUFFER_MAPPED);
}
/*
@@ -1211,30 +898,14 @@ rb_io_buffer_mapped_p(VALUE self)
* If the buffer is _shared_, meaning it references memory that can be shared
* with other processes (and thus might change without being modified
* locally).
- *
- * # Create a test file:
- * File.write('test.txt', 'test')
- *
- * # Create a shared mapping from the given file, the file must be opened in
- * # read-write mode unless we also specify IO::Buffer::READONLY:
- * buffer = IO::Buffer.map(File.open('test.txt', 'r+'), nil, 0)
- * # => #<IO::Buffer 0x00007f1bffd5e000+4 EXTERNAL MAPPED SHARED>
- *
- * # Write to the buffer, which will modify the mapped file:
- * buffer.set_string('b', 0)
- * # => 1
- *
- * # The file itself is modified:
- * File.read('test.txt')
- * # => "best"
*/
static VALUE
rb_io_buffer_shared_p(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return RBOOL(buffer->flags & RB_IO_BUFFER_SHARED);
+ return RBOOL(data->flags & RB_IO_BUFFER_SHARED);
}
/*
@@ -1247,6 +918,8 @@ rb_io_buffer_shared_p(VALUE self)
* Locking is not thread safe, but is a semantic used to ensure buffers don't
* move while being used by a system call.
*
+ * Example:
+ *
* buffer.locked do
* buffer.write(io) # theoretical system call interface
* end
@@ -1254,50 +927,19 @@ rb_io_buffer_shared_p(VALUE self)
static VALUE
rb_io_buffer_locked_p(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- return RBOOL(buffer->flags & RB_IO_BUFFER_LOCKED);
-}
-
-/* call-seq: private? -> true or false
- *
- * If the buffer is _private_, meaning modifications to the buffer will not
- * be replicated to the underlying file mapping.
- *
- * # Create a test file:
- * File.write('test.txt', 'test')
- *
- * # Create a private mapping from the given file. Note that the file here
- * # is opened in read-only mode, but it doesn't matter due to the private
- * # mapping:
- * buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::PRIVATE)
- * # => #<IO::Buffer 0x00007fce63f11000+4 MAPPED PRIVATE>
- *
- * # Write to the buffer (invoking CoW of the underlying file buffer):
- * buffer.set_string('b', 0)
- * # => 1
- *
- * # The file itself is not modified:
- * File.read('test.txt')
- * # => "test"
- */
-static VALUE
-rb_io_buffer_private_p(VALUE self)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return RBOOL(buffer->flags & RB_IO_BUFFER_PRIVATE);
+ return RBOOL(data->flags & RB_IO_BUFFER_LOCKED);
}
int
rb_io_buffer_readonly_p(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return buffer->flags & RB_IO_BUFFER_READONLY;
+ return data->flags & RB_IO_BUFFER_READONLY;
}
/*
@@ -1314,44 +956,32 @@ io_buffer_readonly_p(VALUE self)
return RBOOL(rb_io_buffer_readonly_p(self));
}
-static void
-io_buffer_lock(struct rb_io_buffer *buffer)
-{
- if (buffer->flags & RB_IO_BUFFER_LOCKED) {
- rb_raise(rb_eIOBufferLockedError, "Buffer already locked!");
- }
-
- buffer->flags |= RB_IO_BUFFER_LOCKED;
-}
-
VALUE
rb_io_buffer_lock(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- io_buffer_lock(buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- return self;
-}
-
-static void
-io_buffer_unlock(struct rb_io_buffer *buffer)
-{
- if (!(buffer->flags & RB_IO_BUFFER_LOCKED)) {
- rb_raise(rb_eIOBufferLockedError, "Buffer not locked!");
+ if (data->flags & RB_IO_BUFFER_LOCKED) {
+ rb_raise(rb_eIOBufferLockedError, "Buffer already locked!");
}
- buffer->flags &= ~RB_IO_BUFFER_LOCKED;
+ data->flags |= RB_IO_BUFFER_LOCKED;
+
+ return self;
}
VALUE
rb_io_buffer_unlock(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- io_buffer_unlock(buffer);
+ if (!(data->flags & RB_IO_BUFFER_LOCKED)) {
+ rb_raise(rb_eIOBufferLockedError, "Buffer not locked!");
+ }
+
+ data->flags &= ~RB_IO_BUFFER_LOCKED;
return self;
}
@@ -1359,11 +989,11 @@ rb_io_buffer_unlock(VALUE self)
int
rb_io_buffer_try_unlock(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- if (buffer->flags & RB_IO_BUFFER_LOCKED) {
- buffer->flags &= ~RB_IO_BUFFER_LOCKED;
+ if (data->flags & RB_IO_BUFFER_LOCKED) {
+ data->flags &= ~RB_IO_BUFFER_LOCKED;
return 1;
}
@@ -1384,6 +1014,8 @@ rb_io_buffer_try_unlock(VALUE self)
* non-blocking system calls. You can only share a buffer between threads with
* appropriate synchronisation techniques.
*
+ * Example:
+ *
* buffer = IO::Buffer.new(4)
* buffer.locked? #=> false
*
@@ -1403,18 +1035,18 @@ rb_io_buffer_try_unlock(VALUE self)
VALUE
rb_io_buffer_locked(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- if (buffer->flags & RB_IO_BUFFER_LOCKED) {
+ if (data->flags & RB_IO_BUFFER_LOCKED) {
rb_raise(rb_eIOBufferLockedError, "Buffer already locked!");
}
- buffer->flags |= RB_IO_BUFFER_LOCKED;
+ data->flags |= RB_IO_BUFFER_LOCKED;
VALUE result = rb_yield(self);
- buffer->flags &= ~RB_IO_BUFFER_LOCKED;
+ data->flags &= ~RB_IO_BUFFER_LOCKED;
return result;
}
@@ -1431,6 +1063,8 @@ rb_io_buffer_locked(VALUE self)
*
* You can resize a freed buffer to re-allocate it.
*
+ * Example:
+ *
* buffer = IO::Buffer.for('test')
* buffer.free
* # => #<IO::Buffer 0x0000000000000000+0 NULL>
@@ -1447,25 +1081,14 @@ rb_io_buffer_locked(VALUE self)
VALUE
rb_io_buffer_free(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- if (buffer->flags & RB_IO_BUFFER_LOCKED) {
+ if (data->flags & RB_IO_BUFFER_LOCKED) {
rb_raise(rb_eIOBufferLockedError, "Buffer is locked!");
}
- io_buffer_free(buffer);
-
- 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);
+ io_buffer_free(data);
return self;
}
@@ -1473,83 +1096,36 @@ VALUE rb_io_buffer_free_locked(VALUE self)
// Validate that access to the buffer is within bounds, assuming you want to
// access length bytes from the specified offset.
static inline void
-io_buffer_validate_range(struct rb_io_buffer *buffer, size_t offset, size_t length)
+io_buffer_validate_range(struct rb_io_buffer *data, size_t offset, size_t length)
{
- // We assume here that offset + length won't overflow:
- if (offset + length > buffer->size) {
- rb_raise(rb_eArgError, "Specified offset+length is bigger than the buffer size!");
+ if (offset + length > data->size) {
+ rb_raise(rb_eArgError, "Specified offset+length exceeds data size!");
}
}
-/*
- * call-seq: hexdump([offset, [length, [width]]]) -> string
- *
- * Returns a human-readable string representation of the buffer. The exact
- * format is subject to change.
- *
- * buffer = IO::Buffer.for("Hello World")
- * puts buffer.hexdump
- * # 0x00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 Hello World
- *
- * As buffers are usually fairly big, you may want to limit the output by
- * specifying the offset and length:
- *
- * puts buffer.hexdump(6, 5)
- * # 0x00000006 57 6f 72 6c 64 World
- */
static VALUE
-rb_io_buffer_hexdump(int argc, VALUE *argv, VALUE self)
+rb_io_buffer_slice(struct rb_io_buffer *data, VALUE self, size_t offset, size_t length)
{
- rb_check_arity(argc, 0, 3);
-
- size_t offset, length;
- struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
-
- size_t width = RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH;
- if (argc >= 3) {
- width = io_buffer_extract_width(argv[2], 1);
- }
-
- // This may raise an exception if the offset/length is invalid:
- io_buffer_validate_range(buffer, offset, length);
-
- VALUE result = Qnil;
-
- if (io_buffer_validate(buffer) && buffer->base) {
- result = rb_str_buf_new(io_buffer_hexdump_output_size(width, length, 1));
-
- io_buffer_hexdump(result, width, buffer->base, offset+length, offset, 1);
- }
-
- return result;
-}
-
-static VALUE
-rb_io_buffer_slice(struct rb_io_buffer *buffer, VALUE self, size_t offset, size_t length)
-{
- io_buffer_validate_range(buffer, offset, length);
+ io_buffer_validate_range(data, offset, length);
VALUE instance = rb_io_buffer_type_allocate(rb_class_of(self));
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->base = (char*)data->base + offset;
slice->size = length;
// The source should be the root buffer:
- if (buffer->source != Qnil) {
- RB_OBJ_WRITE(instance, &slice->source, buffer->source);
- }
- else {
- RB_OBJ_WRITE(instance, &slice->source, self);
- }
+ if (data->source != Qnil)
+ slice->source = data->source;
+ else
+ slice->source = self;
return instance;
}
/*
- * call-seq: slice([offset, [length]]) -> io_buffer
+ * call-seq: slice([offset = 0, [length]]) -> io_buffer
*
* Produce another IO::Buffer which is a slice (or view into) the current one
* starting at +offset+ bytes and going for +length+ bytes.
@@ -1567,6 +1143,8 @@ rb_io_buffer_slice(struct rb_io_buffer *buffer, VALUE self, size_t offset, size_
* Raises RuntimeError if the <tt>offset+length</tt> is out of the current
* buffer's bounds.
*
+ * Example:
+ *
* string = 'test'
* buffer = IO::Buffer.for(string)
*
@@ -1607,17 +1185,115 @@ io_buffer_slice(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 0, 2);
- size_t offset, length;
- struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
+
+ size_t offset = 0, length = 0;
+
+ if (argc > 0) {
+ if (rb_int_negative_p(argv[0])) {
+ rb_raise(rb_eArgError, "Offset can't be negative!");
+ }
+
+ offset = NUM2SIZET(argv[0]);
+ }
+
+ if (argc > 1) {
+ if (rb_int_negative_p(argv[1])) {
+ rb_raise(rb_eArgError, "Length can't be negative!");
+ }
+
+ length = NUM2SIZET(argv[1]);
+ } else {
+ length = data->size - offset;
+ }
+
+ return rb_io_buffer_slice(data, self, offset, length);
+}
+
+int
+rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size)
+{
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
+
+ if (io_buffer_validate(data)) {
+ if (data->base) {
+ *base = data->base;
+ *size = data->size;
+
+ return data->flags;
+ }
+ }
+
+ *base = NULL;
+ *size = 0;
+
+ return 0;
+}
+
+static inline void
+io_buffer_get_bytes_for_writing(struct rb_io_buffer *data, void **base, size_t *size)
+{
+ if (data->flags & RB_IO_BUFFER_READONLY) {
+ rb_raise(rb_eIOBufferAccessError, "Buffer is not writable!");
+ }
- return rb_io_buffer_slice(buffer, self, offset, length);
+ if (!io_buffer_validate(data)) {
+ rb_raise(rb_eIOBufferInvalidatedError, "Buffer is invalid!");
+ }
+
+ if (data->base) {
+ *base = data->base;
+ *size = data->size;
+
+ return;
+ }
+
+ rb_raise(rb_eIOBufferAllocationError, "The buffer is not allocated!");
+}
+
+void
+rb_io_buffer_get_bytes_for_writing(VALUE self, void **base, size_t *size)
+{
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
+
+ io_buffer_get_bytes_for_writing(data, base, size);
+}
+
+static void
+io_buffer_get_bytes_for_reading(struct rb_io_buffer *data, const void **base, size_t *size)
+{
+ if (!io_buffer_validate(data)) {
+ rb_raise(rb_eIOBufferInvalidatedError, "Buffer has been invalidated!");
+ }
+
+ if (data->base) {
+ *base = data->base;
+ *size = data->size;
+
+ return;
+ }
+
+ rb_raise(rb_eIOBufferAllocationError, "The buffer is not allocated!");
+}
+
+void
+rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size)
+{
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
+
+ io_buffer_get_bytes_for_reading(data, base, size);
}
/*
* call-seq: transfer -> new_io_buffer
*
- * Transfers ownership of the underlying memory to a new buffer, causing the
- * current buffer to become uninitialized.
+ * Transfers ownership to a new buffer, deallocating the current one.
+ *
+ * Example:
*
* buffer = IO::Buffer.new('test')
* other = buffer.transfer
@@ -1634,10 +1310,10 @@ io_buffer_slice(int argc, VALUE *argv, VALUE self)
VALUE
rb_io_buffer_transfer(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- if (buffer->flags & RB_IO_BUFFER_LOCKED) {
+ if (data->flags & RB_IO_BUFFER_LOCKED) {
rb_raise(rb_eIOBufferLockedError, "Cannot transfer ownership of locked buffer!");
}
@@ -1645,96 +1321,91 @@ rb_io_buffer_transfer(VALUE self)
struct rb_io_buffer *transferred;
TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, transferred);
- *transferred = *buffer;
- io_buffer_zero(buffer);
+ *transferred = *data;
+ io_buffer_zero(data);
return instance;
}
static void
-io_buffer_resize_clear(struct rb_io_buffer *buffer, void* base, size_t size)
+io_buffer_resize_clear(struct rb_io_buffer *data, void* base, size_t size)
{
- if (size > buffer->size) {
- memset((unsigned char*)base+buffer->size, 0, size - buffer->size);
+ if (size > data->size) {
+ memset((unsigned char*)base+data->size, 0, size - data->size);
}
}
static void
-io_buffer_resize_copy(VALUE self, struct rb_io_buffer *buffer, size_t size)
+io_buffer_resize_copy(struct rb_io_buffer *data, size_t size)
{
// Slow path:
struct rb_io_buffer resized;
- io_buffer_initialize(self, &resized, NULL, size, io_flags_for_size(size), Qnil);
+ io_buffer_initialize(&resized, NULL, size, io_flags_for_size(size), Qnil);
- if (buffer->base) {
- size_t preserve = buffer->size;
+ if (data->base) {
+ size_t preserve = data->size;
if (preserve > size) preserve = size;
- memcpy(resized.base, buffer->base, preserve);
+ memcpy(resized.base, data->base, preserve);
- io_buffer_resize_clear(buffer, resized.base, size);
+ io_buffer_resize_clear(data, resized.base, size);
}
- io_buffer_free(buffer);
- *buffer = resized;
+ io_buffer_free(data);
+ *data = resized;
}
void
rb_io_buffer_resize(VALUE self, size_t size)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- if (buffer->flags & RB_IO_BUFFER_LOCKED) {
+ if (data->flags & RB_IO_BUFFER_LOCKED) {
rb_raise(rb_eIOBufferLockedError, "Cannot resize locked buffer!");
}
- if (buffer->base == NULL) {
- io_buffer_initialize(self, buffer, NULL, size, io_flags_for_size(size), Qnil);
+ if (data->base == NULL) {
+ io_buffer_initialize(data, NULL, size, io_flags_for_size(size), Qnil);
return;
}
- if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
+ if (data->flags & RB_IO_BUFFER_EXTERNAL) {
rb_raise(rb_eIOBufferAccessError, "Cannot resize external buffer!");
}
#if defined(HAVE_MREMAP) && defined(MREMAP_MAYMOVE)
- if (buffer->flags & RB_IO_BUFFER_MAPPED) {
- void *base = mremap(buffer->base, buffer->size, size, MREMAP_MAYMOVE);
+ if (data->flags & RB_IO_BUFFER_MAPPED) {
+ void *base = mremap(data->base, data->size, size, MREMAP_MAYMOVE);
if (base == MAP_FAILED) {
rb_sys_fail("rb_io_buffer_resize:mremap");
}
- io_buffer_resize_clear(buffer, base, size);
+ io_buffer_resize_clear(data, base, size);
- buffer->base = base;
- buffer->size = size;
+ data->base = base;
+ data->size = size;
return;
}
#endif
- if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
- if (size == 0) {
- io_buffer_free(buffer);
- return;
- }
-
- void *base = realloc(buffer->base, size);
+ if (data->flags & RB_IO_BUFFER_INTERNAL) {
+ void *base = realloc(data->base, size);
if (!base) {
rb_sys_fail("rb_io_buffer_resize:realloc");
}
- io_buffer_resize_clear(buffer, base, size);
+ io_buffer_resize_clear(data, base, size);
- buffer->base = base;
- buffer->size = size;
+ data->base = base;
+ data->size = size;
return;
}
- io_buffer_resize_copy(self, buffer, size);
+ io_buffer_resize_copy(data, size);
}
/*
@@ -1758,7 +1429,7 @@ rb_io_buffer_resize(VALUE self, size_t size)
static VALUE
io_buffer_resize(VALUE self, VALUE size)
{
- rb_io_buffer_resize(self, io_buffer_extract_size(size));
+ rb_io_buffer_resize(self, NUM2SIZET(size));
return self;
}
@@ -1896,9 +1567,9 @@ IO_BUFFER_DECLARE_TYPE(F64, double, RB_IO_BUFFER_BIG_ENDIAN, DBL2NUM, NUM2DBL, r
#undef IO_BUFFER_DECLARE_TYPE
static inline size_t
-io_buffer_buffer_type_size(ID buffer_type)
+io_buffer_data_type_size(ID data_type)
{
-#define IO_BUFFER_DATA_TYPE_SIZE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return RB_IO_BUFFER_DATA_TYPE_##name##_SIZE;
+#define IO_BUFFER_DATA_TYPE_SIZE(name) if (data_type == RB_IO_BUFFER_DATA_TYPE_##name) return RB_IO_BUFFER_DATA_TYPE_##name##_SIZE;
IO_BUFFER_DATA_TYPE_SIZE(U8)
IO_BUFFER_DATA_TYPE_SIZE(S8)
IO_BUFFER_DATA_TYPE_SIZE(u16)
@@ -1924,33 +1595,34 @@ io_buffer_buffer_type_size(ID buffer_type)
/*
* call-seq:
- * size_of(buffer_type) -> byte size
- * size_of(array of buffer_type) -> byte size
+ * size_of(data_type) -> byte size
+ * size_of(array of data_type) -> byte size
+ *
+ * Returns the size of the given data type(s) in bytes.
*
- * Returns the size of the given buffer type(s) in bytes.
+ * Example:
*
* IO::Buffer.size_of(:u32) # => 4
* IO::Buffer.size_of([:u32, :u32]) # => 8
*/
static VALUE
-io_buffer_size_of(VALUE klass, VALUE buffer_type)
+io_buffer_size_of(VALUE klass, VALUE data_type)
{
- if (RB_TYPE_P(buffer_type, T_ARRAY)) {
+ if (RB_TYPE_P(data_type, T_ARRAY)) {
size_t total = 0;
- for (long i = 0; i < RARRAY_LEN(buffer_type); i++) {
- total += io_buffer_buffer_type_size(RB_SYM2ID(RARRAY_AREF(buffer_type, i)));
+ for (long i = 0; i < RARRAY_LEN(data_type); i++) {
+ total += io_buffer_data_type_size(RB_SYM2ID(RARRAY_AREF(data_type, i)));
}
return SIZET2NUM(total);
- }
- else {
- return SIZET2NUM(io_buffer_buffer_type_size(RB_SYM2ID(buffer_type)));
+ } else {
+ return SIZET2NUM(io_buffer_data_type_size(RB_SYM2ID(data_type)));
}
}
static inline VALUE
-rb_io_buffer_get_value(const void* base, size_t size, ID buffer_type, size_t *offset)
+rb_io_buffer_get_value(const void* base, size_t size, ID data_type, size_t *offset)
{
-#define IO_BUFFER_GET_VALUE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return io_buffer_read_##name(base, size, offset);
+#define IO_BUFFER_GET_VALUE(name) if (data_type == RB_IO_BUFFER_DATA_TYPE_##name) return io_buffer_read_##name(base, size, offset);
IO_BUFFER_GET_VALUE(U8)
IO_BUFFER_GET_VALUE(S8)
@@ -1979,9 +1651,9 @@ rb_io_buffer_get_value(const void* base, size_t size, ID buffer_type, size_t *of
}
/*
- * call-seq: get_value(buffer_type, offset) -> numeric
+ * call-seq: get_value(data_type, offset) -> numeric
*
- * Read from buffer a value of +type+ at +offset+. +buffer_type+ should be one
+ * Read from buffer a value of +type+ at +offset+. +data_type+ should be one
* of symbols:
*
* * +:U8+: unsigned integer, 1 byte
@@ -2003,10 +1675,12 @@ rb_io_buffer_get_value(const void* base, size_t size, ID buffer_type, size_t *of
* * +:f64+: double, 8 bytes, little-endian
* * +:F64+: double, 8 bytes, big-endian
*
- * A buffer type refers specifically to the type of binary buffer that is stored
- * in the buffer. For example, a +:u32+ buffer type is a 32-bit unsigned
+ * A data type refers specifically to the type of binary data that is stored
+ * in the buffer. For example, a +:u32+ data type is a 32-bit unsigned
* integer in little-endian format.
*
+ * Example:
+ *
* string = [1.5].pack('f')
* # => "\x00\x00\xC0?"
* IO::Buffer.for(string).get_value(:f32, 0)
@@ -2017,7 +1691,7 @@ io_buffer_get_value(VALUE self, VALUE type, VALUE _offset)
{
const void *base;
size_t size;
- size_t offset = io_buffer_extract_offset(_offset);
+ size_t offset = NUM2SIZET(_offset);
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
@@ -2025,32 +1699,34 @@ io_buffer_get_value(VALUE self, VALUE type, VALUE _offset)
}
/*
- * call-seq: get_values(buffer_types, offset) -> array
+ * call-seq: get_values(data_types, offset) -> array
*
- * Similar to #get_value, except that it can handle multiple buffer types and
+ * Similar to #get_value, except that it can handle multiple data types and
* returns an array of values.
*
+ * Example:
+ *
* string = [1.5, 2.5].pack('ff')
* IO::Buffer.for(string).get_values([:f32, :f32], 0)
* # => [1.5, 2.5]
*/
static VALUE
-io_buffer_get_values(VALUE self, VALUE buffer_types, VALUE _offset)
+io_buffer_get_values(VALUE self, VALUE data_types, VALUE _offset)
{
- size_t offset = io_buffer_extract_offset(_offset);
+ size_t offset = NUM2SIZET(_offset);
const void *base;
size_t size;
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
- if (!RB_TYPE_P(buffer_types, T_ARRAY)) {
- rb_raise(rb_eArgError, "Argument buffer_types should be an array!");
+ if (!RB_TYPE_P(data_types, T_ARRAY)) {
+ rb_raise(rb_eArgError, "Argument data_types should be an array!");
}
- VALUE array = rb_ary_new_capa(RARRAY_LEN(buffer_types));
+ VALUE array = rb_ary_new_capa(RARRAY_LEN(data_types));
- for (long i = 0; i < RARRAY_LEN(buffer_types); i++) {
- VALUE type = rb_ary_entry(buffer_types, i);
+ for (long i = 0; i < RARRAY_LEN(data_types); i++) {
+ VALUE type = rb_ary_entry(data_types, i);
VALUE value = rb_io_buffer_get_value(base, size, RB_SYM2ID(type), &offset);
rb_ary_push(array, value);
}
@@ -2058,50 +1734,18 @@ io_buffer_get_values(VALUE self, VALUE buffer_types, VALUE _offset)
return array;
}
-// Extract a count argument, which must be a positive integer.
-// Count is generally considered relative to the number of things.
-static inline size_t
-io_buffer_extract_count(VALUE argument)
-{
- if (rb_int_negative_p(argument)) {
- rb_raise(rb_eArgError, "Count can't be negative!");
- }
-
- return NUM2SIZET(argument);
-}
-
-static inline void
-io_buffer_extract_offset_count(ID buffer_type, size_t size, int argc, VALUE *argv, size_t *offset, size_t *count)
-{
- if (argc >= 1) {
- *offset = io_buffer_extract_offset(argv[0]);
- }
- else {
- *offset = 0;
- }
-
- if (argc >= 2) {
- *count = io_buffer_extract_count(argv[1]);
- }
- else {
- if (*offset > size) {
- rb_raise(rb_eArgError, "The given offset is bigger than the buffer size!");
- }
-
- *count = (size - *offset) / io_buffer_buffer_type_size(buffer_type);
- }
-}
-
/*
* call-seq:
- * each(buffer_type, [offset, [count]]) {|offset, value| ...} -> self
- * each(buffer_type, [offset, [count]]) -> enumerator
+ * each(data_type, [offset, [count]]) {|offset, value| ...} -> self
+ * each(data_type, [offset, [count]]) -> enumerator
*
- * Iterates over the buffer, yielding each +value+ of +buffer_type+ starting
+ * Iterates over the buffer, yielding each +value+ of +data_type+ starting
* from +offset+.
*
* If +count+ is given, only +count+ values will be yielded.
*
+ * Example:
+ *
* IO::Buffer.for("Hello World").each(:U8, 2, 2) do |offset, value|
* puts "#{offset}: #{value}"
* end
@@ -2118,20 +1762,30 @@ io_buffer_each(int argc, VALUE *argv, VALUE self)
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
- ID buffer_type;
+ ID data_type;
if (argc >= 1) {
- buffer_type = RB_SYM2ID(argv[0]);
+ data_type = RB_SYM2ID(argv[0]);
+ } else {
+ data_type = RB_IO_BUFFER_DATA_TYPE_U8;
}
- else {
- buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
+
+ size_t offset;
+ if (argc >= 2) {
+ offset = NUM2SIZET(argv[1]);
+ } else {
+ offset = 0;
}
- size_t offset, count;
- io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
+ size_t count;
+ if (argc >= 3) {
+ count = NUM2SIZET(argv[2]);
+ } else {
+ count = (size - offset) / io_buffer_data_type_size(data_type);
+ }
for (size_t i = 0; i < count; i++) {
size_t current_offset = offset;
- VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
+ VALUE value = rb_io_buffer_get_value(base, size, data_type, &offset);
rb_yield_values(2, SIZET2NUM(current_offset), value);
}
@@ -2139,12 +1793,14 @@ io_buffer_each(int argc, VALUE *argv, VALUE self)
}
/*
- * call-seq: values(buffer_type, [offset, [count]]) -> array
+ * call-seq: values(data_type, [offset, [count]]) -> array
*
- * Returns an array of values of +buffer_type+ starting from +offset+.
+ * Returns an array of values of +data_type+ starting from +offset+.
*
* If +count+ is given, only +count+ values will be returned.
*
+ * Example:
+ *
* IO::Buffer.for("Hello World").values(:U8, 2, 2)
* # => [108, 108]
*/
@@ -2156,21 +1812,31 @@ io_buffer_values(int argc, VALUE *argv, VALUE self)
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
- ID buffer_type;
+ ID data_type;
if (argc >= 1) {
- buffer_type = RB_SYM2ID(argv[0]);
+ data_type = RB_SYM2ID(argv[0]);
+ } else {
+ data_type = RB_IO_BUFFER_DATA_TYPE_U8;
}
- else {
- buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
+
+ size_t offset;
+ if (argc >= 2) {
+ offset = NUM2SIZET(argv[1]);
+ } else {
+ offset = 0;
}
- size_t offset, count;
- io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
+ size_t count;
+ if (argc >= 3) {
+ count = NUM2SIZET(argv[2]);
+ } else {
+ count = (size - offset) / io_buffer_data_type_size(data_type);
+ }
VALUE array = rb_ary_new_capa(count);
for (size_t i = 0; i < count; i++) {
- VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
+ VALUE value = rb_io_buffer_get_value(base, size, data_type, &offset);
rb_ary_push(array, value);
}
@@ -2186,6 +1852,8 @@ io_buffer_values(int argc, VALUE *argv, VALUE self)
*
* If +count+ is given, only +count+ bytes will be yielded.
*
+ * Example:
+ *
* IO::Buffer.for("Hello World").each_byte(2, 2) do |offset, byte|
* puts "#{offset}: #{byte}"
* end
@@ -2202,8 +1870,19 @@ io_buffer_each_byte(int argc, VALUE *argv, VALUE self)
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
- size_t offset, count;
- io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc-1, argv+1, &offset, &count);
+ size_t offset;
+ if (argc >= 2) {
+ offset = NUM2SIZET(argv[1]);
+ } else {
+ offset = 0;
+ }
+
+ size_t count;
+ if (argc >= 3) {
+ count = NUM2SIZET(argv[2]);
+ } else {
+ count = (size - offset);
+ }
for (size_t i = 0; i < count; i++) {
unsigned char *value = (unsigned char *)base + i + offset;
@@ -2214,9 +1893,9 @@ io_buffer_each_byte(int argc, VALUE *argv, VALUE self)
}
static inline void
-rb_io_buffer_set_value(const void* base, size_t size, ID buffer_type, size_t *offset, VALUE value)
+rb_io_buffer_set_value(const void* base, size_t size, ID data_type, size_t *offset, VALUE value)
{
-#define IO_BUFFER_SET_VALUE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) {io_buffer_write_##name(base, size, offset, value); return;}
+#define IO_BUFFER_SET_VALUE(name) if (data_type == RB_IO_BUFFER_DATA_TYPE_##name) {io_buffer_write_##name(base, size, offset, value); return;}
IO_BUFFER_SET_VALUE(U8);
IO_BUFFER_SET_VALUE(S8);
@@ -2279,7 +1958,7 @@ io_buffer_set_value(VALUE self, VALUE type, VALUE _offset, VALUE value)
{
void *base;
size_t size;
- size_t offset = io_buffer_extract_offset(_offset);
+ size_t offset = NUM2SIZET(_offset);
rb_io_buffer_get_bytes_for_writing(self, &base, &size);
@@ -2289,12 +1968,14 @@ io_buffer_set_value(VALUE self, VALUE type, VALUE _offset, VALUE value)
}
/*
- * call-seq: set_values(buffer_types, offset, values) -> offset
+ * call-seq: set_values(data_types, offset, values) -> offset
*
- * Write +values+ of +buffer_types+ at +offset+ to the buffer. +buffer_types+
+ * Write +values+ of +data_types+ at +offset+ to the buffer. +data_types+
* should be an array of symbols as described in #get_value. +values+ should
* be an array of values to write.
*
+ * Example:
+ *
* buffer = IO::Buffer.new(8)
* buffer.set_values([:U8, :U16], 0, [1, 2])
* buffer
@@ -2303,28 +1984,28 @@ io_buffer_set_value(VALUE self, VALUE type, VALUE _offset, VALUE value)
* # 0x00000000 01 00 02 00 00 00 00 00 ........
*/
static VALUE
-io_buffer_set_values(VALUE self, VALUE buffer_types, VALUE _offset, VALUE values)
+io_buffer_set_values(VALUE self, VALUE data_types, VALUE _offset, VALUE values)
{
- if (!RB_TYPE_P(buffer_types, T_ARRAY)) {
- rb_raise(rb_eArgError, "Argument buffer_types should be an array!");
+ if (!RB_TYPE_P(data_types, T_ARRAY)) {
+ rb_raise(rb_eArgError, "Argument data_types should be an array!");
}
if (!RB_TYPE_P(values, T_ARRAY)) {
rb_raise(rb_eArgError, "Argument values should be an array!");
}
- if (RARRAY_LEN(buffer_types) != RARRAY_LEN(values)) {
- rb_raise(rb_eArgError, "Argument buffer_types and values should have the same length!");
+ if (RARRAY_LEN(data_types) != RARRAY_LEN(values)) {
+ rb_raise(rb_eArgError, "Argument data_types and values should have the same length!");
}
- size_t offset = io_buffer_extract_offset(_offset);
+ size_t offset = NUM2SIZET(_offset);
void *base;
size_t size;
rb_io_buffer_get_bytes_for_writing(self, &base, &size);
- for (long i = 0; i < RARRAY_LEN(buffer_types); i++) {
- VALUE type = rb_ary_entry(buffer_types, i);
+ for (long i = 0; i < RARRAY_LEN(data_types); i++) {
+ VALUE type = rb_ary_entry(data_types, i);
VALUE value = rb_ary_entry(values, i);
rb_io_buffer_set_value(base, size, RB_SYM2ID(type), &offset, value);
}
@@ -2333,16 +2014,16 @@ io_buffer_set_values(VALUE self, VALUE buffer_types, VALUE _offset, VALUE values
}
static void
-io_buffer_memcpy(struct rb_io_buffer *buffer, size_t offset, const void *source_base, size_t source_offset, size_t source_size, size_t length)
+io_buffer_memcpy(struct rb_io_buffer *data, size_t offset, const void *source_base, size_t source_offset, size_t source_size, size_t length)
{
void *base;
size_t size;
- io_buffer_get_bytes_for_writing(buffer, &base, &size);
+ io_buffer_get_bytes_for_writing(data, &base, &size);
- io_buffer_validate_range(buffer, offset, length);
+ io_buffer_validate_range(data, offset, length);
if (source_offset + length > source_size) {
- rb_raise(rb_eArgError, "The computed source range exceeds the size of the source buffer!");
+ rb_raise(rb_eArgError, "The computed source range exceeds the size of the source!");
}
memcpy((unsigned char*)base+offset, (unsigned char*)source_base+source_offset, length);
@@ -2350,20 +2031,23 @@ io_buffer_memcpy(struct rb_io_buffer *buffer, size_t offset, const void *source_
// (offset, length, source_offset) -> length
static VALUE
-io_buffer_copy_from(struct rb_io_buffer *buffer, const void *source_base, size_t source_size, int argc, VALUE *argv)
+io_buffer_copy_from(struct rb_io_buffer *data, const void *source_base, size_t source_size, int argc, VALUE *argv)
{
- size_t offset = 0;
+ size_t offset;
size_t length;
size_t source_offset;
// The offset we copy into the buffer:
if (argc >= 1) {
- offset = io_buffer_extract_offset(argv[0]);
+ offset = NUM2SIZET(argv[0]);
+ }
+ else {
+ offset = 0;
}
// The offset we start from within the string:
if (argc >= 3) {
- source_offset = io_buffer_extract_offset(argv[2]);
+ source_offset = NUM2SIZET(argv[2]);
if (source_offset > source_size) {
rb_raise(rb_eArgError, "The given source offset is bigger than the source itself!");
@@ -2375,14 +2059,14 @@ io_buffer_copy_from(struct rb_io_buffer *buffer, const void *source_base, size_t
// The length we are going to copy:
if (argc >= 2 && !RB_NIL_P(argv[1])) {
- length = io_buffer_extract_length(argv[1]);
+ length = NUM2SIZET(argv[1]);
}
else {
// Default to the source offset -> source size:
length = source_size - source_offset;
}
- io_buffer_memcpy(buffer, offset, source_base, source_offset, source_size, length);
+ io_buffer_memcpy(data, offset, source_base, source_offset, source_size, length);
return SIZET2NUM(length);
}
@@ -2407,25 +2091,25 @@ io_buffer_copy_from(struct rb_io_buffer *buffer, const void *source_base, size_t
static VALUE
rb_io_buffer_initialize_copy(VALUE self, VALUE source)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
const void *source_base;
size_t source_size;
rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
- io_buffer_initialize(self, buffer, NULL, source_size, io_flags_for_size(source_size), Qnil);
+ io_buffer_initialize(data, NULL, source_size, io_flags_for_size(source_size), Qnil);
- return io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
+ return io_buffer_copy_from(data, source_base, source_size, 0, NULL);
}
/*
* 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 data from a source IO::Buffer into the buffer,
+ * at +offset+ using +memcpy+. For copying String instances, see #set_string.
*
* buffer = IO::Buffer.new(32)
* # =>
@@ -2434,22 +2118,22 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source)
* # 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ *
*
* buffer.copy(IO::Buffer.for("test"), 8)
- * # => 4 -- size of buffer copied
+ * # => 4 -- size of data copied
* buffer
* # =>
* # #<IO::Buffer 0x0000555f5cf8fe40+32 INTERNAL>
* # 0x00000000 00 00 00 00 00 00 00 00 74 65 73 74 00 00 00 00 ........test....
* # 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ *
*
- * #copy can be used to put buffer into strings associated with buffer:
+ * #copy can be used to put data into strings associated with buffer:
*
- * string= "buffer: "
- * # => "buffer: "
+ * string= "data: "
+ * # => "data: "
* buffer = IO::Buffer.for(string)
* buffer.copy(IO::Buffer.for("test"), 5)
* # => 4
* string
- * # => "buffer:test"
+ * # => "data:test"
*
* Attempt to copy into a read-only buffer will fail:
*
@@ -2467,20 +2151,20 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source)
* File.read('test.txt')
* # => "boom"
*
- * Attempt to copy the buffer which will need place outside of buffer's
+ * Attempt to copy the data which will need place outside of buffer's
* bounds will fail:
*
* buffer = IO::Buffer.new(2)
* buffer.copy(IO::Buffer.for('test'), 0)
- * # in `copy': Specified offset+length is bigger than the buffer size! (ArgumentError)
+ * # in `copy': Specified offset+length exceeds source size! (ArgumentError)
*/
static VALUE
io_buffer_copy(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, 4);
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
VALUE source = argv[0];
const void *source_base;
@@ -2488,7 +2172,7 @@ io_buffer_copy(int argc, VALUE *argv, VALUE self)
rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
- return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
+ return io_buffer_copy_from(data, source_base, source_size, argc-1, argv+1);
}
/*
@@ -2510,22 +2194,33 @@ io_buffer_get_string(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 0, 3);
- size_t offset, length;
- struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
const void *base;
size_t size;
- io_buffer_get_bytes_for_reading(buffer, &base, &size);
+ io_buffer_get_bytes_for_reading(data, &base, &size);
- rb_encoding *encoding;
- if (argc >= 3) {
- encoding = rb_find_encoding(argv[2]);
+ size_t offset = 0;
+ size_t length = size;
+ rb_encoding *encoding = rb_ascii8bit_encoding();
+
+ if (argc >= 1) {
+ offset = NUM2SIZET(argv[0]);
+ }
+
+ if (argc >= 2 && !RB_NIL_P(argv[1])) {
+ length = NUM2SIZET(argv[1]);
}
else {
- encoding = rb_ascii8bit_encoding();
+ length = size - offset;
}
- io_buffer_validate_range(buffer, offset, length);
+ if (argc >= 3) {
+ encoding = rb_find_encoding(argv[2]);
+ }
+
+ io_buffer_validate_range(data, offset, length);
return rb_enc_str_new((const char*)base + offset, length, encoding);
}
@@ -2533,15 +2228,15 @@ io_buffer_get_string(int argc, VALUE *argv, VALUE self)
/*
* call-seq: set_string(string, [offset, [length, [source_offset]]]) -> size
*
- * Efficiently copy from a source String into the buffer, at +offset+ using
- * +memcpy+.
+ * Efficiently copy data from a source String into the buffer,
+ * at +offset+ using +memcpy+.
*
* buf = IO::Buffer.new(8)
* # =>
* # #<IO::Buffer 0x0000557412714a20+8 INTERNAL>
* # 0x00000000 00 00 00 00 00 00 00 00 ........
*
- * # set buffer starting from offset 1, take 2 bytes starting from string's
+ * # set data starting from offset 1, take 2 bytes starting from string's
* # second
* buf.set_string('test', 1, 2, 1)
* # => 2
@@ -2558,28 +2253,28 @@ io_buffer_set_string(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, 4);
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
VALUE string = rb_str_to_str(argv[0]);
const void *source_base = RSTRING_PTR(string);
size_t source_size = RSTRING_LEN(string);
- return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
+ return io_buffer_copy_from(data, source_base, source_size, argc-1, argv+1);
}
void
rb_io_buffer_clear(VALUE self, uint8_t value, size_t offset, size_t length)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
void *base;
size_t size;
- io_buffer_get_bytes_for_writing(buffer, &base, &size);
- io_buffer_validate_range(buffer, offset, length);
+ rb_io_buffer_get_bytes_for_writing(self, &base, &size);
+
+ if (offset + length > size) {
+ rb_raise(rb_eArgError, "The given offset + length out of bounds!");
+ }
memset((char*)base + offset, value, length);
}
@@ -2620,13 +2315,26 @@ io_buffer_clear(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 0, 3);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
+
uint8_t value = 0;
if (argc >= 1) {
value = NUM2UINT(argv[0]);
}
- size_t offset, length;
- io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
+ size_t offset = 0;
+ if (argc >= 2) {
+ offset = NUM2SIZET(argv[1]);
+ }
+
+ size_t length;
+ if (argc >= 3) {
+ length = NUM2SIZET(argv[2]);
+ }
+ else {
+ length = data->size - offset;
+ }
rb_io_buffer_clear(self, value, offset, length);
@@ -2658,90 +2366,18 @@ io_buffer_default_size(size_t page_size)
return platform_agnostic_default_size;
}
-struct io_buffer_blocking_region_argument {
- struct rb_io_buffer *buffer;
- rb_blocking_function_t *function;
- void *data;
- int descriptor;
-};
-
-static VALUE
-io_buffer_blocking_region_begin(VALUE _argument)
-{
- struct io_buffer_blocking_region_argument *argument = (void*)_argument;
-
- return rb_thread_io_blocking_region(argument->function, argument->data, argument->descriptor);
-}
-
-static VALUE
-io_buffer_blocking_region_ensure(VALUE _argument)
-{
- struct io_buffer_blocking_region_argument *argument = (void*)_argument;
-
- io_buffer_unlock(argument->buffer);
-
- return Qnil;
-}
-
-static VALUE
-io_buffer_blocking_region(struct rb_io_buffer *buffer, rb_blocking_function_t *function, void *data, int descriptor)
-{
- struct io_buffer_blocking_region_argument argument = {
- .buffer = buffer,
- .function = function,
- .data = data,
- .descriptor = descriptor,
- };
-
- // If the buffer is already locked, we can skip the ensure (unlock):
- if (buffer->flags & RB_IO_BUFFER_LOCKED) {
- return io_buffer_blocking_region_begin((VALUE)&argument);
- }
- else {
- // The buffer should be locked for the duration of the blocking region:
- io_buffer_lock(buffer);
-
- return rb_ensure(io_buffer_blocking_region_begin, (VALUE)&argument, io_buffer_blocking_region_ensure, (VALUE)&argument);
- }
-}
-
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:
+ void *base;
size_t size;
- // The minimum number of bytes to read:
- size_t length;
};
static VALUE
io_buffer_read_internal(void *_argument)
{
- size_t total = 0;
struct io_buffer_read_internal_argument *argument = _argument;
-
- while (true) {
- ssize_t result = read(argument->descriptor, argument->base, argument->size);
-
- 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 (total >= argument->length) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
-
- argument->base = argument->base + result;
- argument->size = argument->size - result;
- }
- }
+ ssize_t result = read(argument->descriptor, argument->base, argument->size);
+ return rb_fiber_scheduler_io_result(result, errno);
}
VALUE
@@ -2749,50 +2385,48 @@ rb_io_buffer_read(VALUE self, VALUE io, size_t length, size_t offset)
{
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_read(scheduler, io, self, length, offset);
+ VALUE result = rb_fiber_scheduler_io_read(scheduler, io, self, SIZET2NUM(length), SIZET2NUM(offset));
if (!UNDEF_P(result)) {
return result;
}
}
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- io_buffer_validate_range(buffer, offset, length);
+ io_buffer_validate_range(data, offset, length);
int descriptor = rb_io_descriptor(io);
void * base;
size_t size;
- io_buffer_get_bytes_for_writing(buffer, &base, &size);
+ io_buffer_get_bytes_for_writing(data, &base, &size);
base = (unsigned char*)base + offset;
- size = size - offset;
struct io_buffer_read_internal_argument argument = {
.descriptor = descriptor,
.base = base,
- .size = size,
- .length = length,
+ .size = length,
};
- return io_buffer_blocking_region(buffer, io_buffer_read_internal, &argument, descriptor);
+ return rb_thread_io_blocking_region(io_buffer_read_internal, &argument, descriptor);
}
/*
* call-seq: read(io, [length, [offset]]) -> read length or -errno
*
- * Read at least +length+ bytes from the +io+, into the buffer starting at
+ * Read at most +length+ bytes from +io+ 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.
+ * If +length+ is not given, read until the end of the buffer.
*
- * If +length+ is zero, exactly one <tt>read</tt> operation will occur.
+ * If +offset+ is not given, read from the beginning of the buffer.
*
- * If +offset+ is not given, it defaults to zero, i.e. the beginning of the
- * buffer.
+ * If +length+ is 0, read nothing.
+ *
+ * Example:
*
* IO::Buffer.for('test') do |buffer|
* p buffer
@@ -2809,56 +2443,61 @@ rb_io_buffer_read(VALUE self, VALUE io, size_t length, size_t offset)
static VALUE
io_buffer_read(int argc, VALUE *argv, VALUE self)
{
- rb_check_arity(argc, 1, 3);
+ rb_check_arity(argc, 2, 3);
VALUE io = argv[0];
- size_t length, offset;
- io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
+ size_t length;
+ if (argc >= 2) {
+ if (rb_int_negative_p(argv[1])) {
+ rb_raise(rb_eArgError, "Length can't be negative!");
+ }
+
+ length = NUM2SIZET(argv[1]);
+ }
+
+ size_t offset = 0;
+ if (argc >= 3) {
+ if (rb_int_negative_p(argv[2])) {
+ rb_raise(rb_eArgError, "Offset can't be negative!");
+ }
+
+ offset = NUM2SIZET(argv[2]);
+ }
return rb_io_buffer_read(self, io, length, offset);
}
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
@@ -2866,52 +2505,50 @@ rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t of
{
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_pread(scheduler, io, from, self, length, offset);
+ VALUE result = rb_fiber_scheduler_io_pread(scheduler, io, OFFT2NUM(from), self, SIZET2NUM(length), SIZET2NUM(offset));
if (!UNDEF_P(result)) {
return result;
}
}
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- io_buffer_validate_range(buffer, offset, length);
+ io_buffer_validate_range(data, offset, length);
int descriptor = rb_io_descriptor(io);
void * base;
size_t size;
- io_buffer_get_bytes_for_writing(buffer, &base, &size);
-
- base = (unsigned char*)base + offset;
- size = size - offset;
+ io_buffer_get_bytes_for_writing(data, &base, &size);
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 data we want to read:
+ .size = length,
+
+ // From the offset in the file we want to read from:
.offset = from,
};
- return io_buffer_blocking_region(buffer, io_buffer_pread_internal, &argument, descriptor);
+ return rb_thread_io_blocking_region(io_buffer_pread_internal, &argument, descriptor);
}
/*
- * 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>.
+ * call-seq: pread(io, from, length, [offset]) -> read length or -errno
*
- * 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, put it at the beginning of the buffer.
*
- * 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
@@ -2931,54 +2568,41 @@ rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t of
static VALUE
io_buffer_pread(int argc, VALUE *argv, VALUE self)
{
- rb_check_arity(argc, 2, 4);
+ rb_check_arity(argc, 3, 4);
VALUE io = argv[0];
rb_off_t from = NUM2OFFT(argv[1]);
- size_t length, offset;
- io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
+ size_t length;
+ if (rb_int_negative_p(argv[2])) {
+ rb_raise(rb_eArgError, "Length can't be negative!");
+ }
+ length = NUM2SIZET(argv[2]);
+
+ size_t offset = 0;
+ if (argc >= 4) {
+ if (rb_int_negative_p(argv[3])) {
+ rb_raise(rb_eArgError, "Offset can't be negative!");
+ }
+
+ offset = NUM2SIZET(argv[3]);
+ }
return rb_io_buffer_pread(self, io, from, length, offset);
}
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:
+ const void *base;
size_t size;
- // The minimum length to write:
- size_t length;
};
static VALUE
io_buffer_write_internal(void *_argument)
{
- size_t total = 0;
struct io_buffer_write_internal_argument *argument = _argument;
-
- while (true) {
- ssize_t result = write(argument->descriptor, argument->base, argument->size);
-
- 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 (total >= argument->length) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
-
- argument->base = argument->base + result;
- argument->size = argument->size - result;
- }
- }
+ ssize_t result = write(argument->descriptor, argument->base, argument->size);
+ return rb_fiber_scheduler_io_result(result, errno);
}
VALUE
@@ -2986,50 +2610,43 @@ rb_io_buffer_write(VALUE self, VALUE io, size_t length, size_t offset)
{
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_write(scheduler, io, self, length, offset);
+ VALUE result = rb_fiber_scheduler_io_write(scheduler, io, self, SIZET2NUM(length), SIZET2NUM(offset));
if (!UNDEF_P(result)) {
return result;
}
}
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- io_buffer_validate_range(buffer, offset, length);
+ io_buffer_validate_range(data, offset, length);
int descriptor = rb_io_descriptor(io);
const void * base;
size_t size;
- io_buffer_get_bytes_for_reading(buffer, &base, &size);
+ io_buffer_get_bytes_for_reading(data, &base, &size);
- base = (unsigned char*)base + offset;
- size = size - offset;
+ base = (unsigned char *)base + offset;
struct io_buffer_write_internal_argument argument = {
.descriptor = descriptor,
.base = base,
- .size = size,
- .length = length,
+ .size = length,
};
- return io_buffer_blocking_region(buffer, io_buffer_write_internal, &argument, descriptor);
+ return rb_thread_io_blocking_region(io_buffer_write_internal, &argument, descriptor);
}
/*
- * call-seq: write(io, [length, [offset]]) -> written length or -errno
+ * call-seq: write(io, length, [offset]) -> written length or -errno
*
- * Write at least +length+ bytes from the buffer starting at +offset+, into the +io+.
- * 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.
+ * Writes +length+ bytes from buffer into +io+, starting at
+ * +offset+ in the buffer. If an error occurs, return <tt>-errno</tt>.
*
- * If +length+ is zero, exactly one <tt>write</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, the bytes are taken from the beginning
+ * of the buffer.
*
* out = File.open('output.txt', 'wb')
* IO::Buffer.for('1234567').write(out, 3)
@@ -3039,55 +2656,61 @@ rb_io_buffer_write(VALUE self, VALUE io, size_t length, size_t offset)
static VALUE
io_buffer_write(int argc, VALUE *argv, VALUE self)
{
- rb_check_arity(argc, 1, 3);
+ rb_check_arity(argc, 2, 3);
VALUE io = argv[0];
- size_t length, offset;
- io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
+ size_t length;
+ if (argc >= 2) {
+ if (rb_int_negative_p(argv[1])) {
+ rb_raise(rb_eArgError, "Length can't be negative!");
+ }
+
+ length = NUM2SIZET(argv[1]);
+ }
+
+ size_t offset = 0;
+ if (argc >= 3) {
+ if (rb_int_negative_p(argv[2])) {
+ rb_raise(rb_eArgError, "Offset can't be negative!");
+ }
+
+ offset = NUM2SIZET(argv[2]);
+ }
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
@@ -3095,63 +2718,49 @@ rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t o
{
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_pwrite(scheduler, io, from, self, length, offset);
+ VALUE result = rb_fiber_scheduler_io_pwrite(scheduler, io, OFFT2NUM(from), self, SIZET2NUM(length), SIZET2NUM(offset));
if (!UNDEF_P(result)) {
return result;
}
}
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- io_buffer_validate_range(buffer, offset, length);
+ io_buffer_validate_range(data, offset, length);
int descriptor = rb_io_descriptor(io);
const void * base;
size_t size;
- io_buffer_get_bytes_for_reading(buffer, &base, &size);
-
- base = (unsigned char*)base + offset;
- size = size - offset;
+ io_buffer_get_bytes_for_reading(data, &base, &size);
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,
+ // And the size to the length of data we want to read:
+ .size = length,
// And the offset in the file we want to write from:
.offset = from,
};
- return io_buffer_blocking_region(buffer, io_buffer_pwrite_internal, &argument, descriptor);
+ return rb_thread_io_blocking_region(io_buffer_pwrite_internal, &argument, descriptor);
}
/*
- * 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>.
+ * call-seq: pwrite(io, from, length, [offset]) -> written length or -errno
*
- * If +length+ is not given or +nil+, it defaults to the size of the buffer
- * minus the offset, i.e. the entire buffer.
+ * Writes +length+ bytes from buffer into +io+, starting at
+ * +offset+ in the buffer. If an error occurs, return <tt>-errno</tt>.
*
- * 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.
+ * 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)
@@ -3162,13 +2771,25 @@ rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t o
static VALUE
io_buffer_pwrite(int argc, VALUE *argv, VALUE self)
{
- rb_check_arity(argc, 2, 4);
+ rb_check_arity(argc, 3, 4);
VALUE io = argv[0];
rb_off_t from = NUM2OFFT(argv[1]);
- size_t length, offset;
- io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
+ size_t length;
+ if (rb_int_negative_p(argv[2])) {
+ rb_raise(rb_eArgError, "Length can't be negative!");
+ }
+ length = NUM2SIZET(argv[2]);
+
+ size_t offset = 0;
+ if (argc >= 4) {
+ if (rb_int_negative_p(argv[3])) {
+ rb_raise(rb_eArgError, "Offset can't be negative!");
+ }
+
+ offset = NUM2SIZET(argv[3]);
+ }
return rb_io_buffer_pwrite(self, io, from, length, offset);
}
@@ -3203,19 +2824,19 @@ memory_and(unsigned char * restrict output, unsigned char * restrict base, size_
static VALUE
io_buffer_and(VALUE self, VALUE mask)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- struct rb_io_buffer *mask_buffer = NULL;
- TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
+ struct rb_io_buffer *mask_data = NULL;
+ TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_data);
- io_buffer_check_mask(mask_buffer);
+ io_buffer_check_mask(mask_data);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
- struct rb_io_buffer *output_buffer = NULL;
- TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
+ VALUE output = rb_io_buffer_new(NULL, data->size, io_flags_for_size(data->size));
+ struct rb_io_buffer *output_data = NULL;
+ TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_data);
- memory_and(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
+ memory_and(output_data->base, data->base, data->size, mask_data->base, mask_data->size);
return output;
}
@@ -3243,19 +2864,19 @@ memory_or(unsigned char * restrict output, unsigned char * restrict base, size_t
static VALUE
io_buffer_or(VALUE self, VALUE mask)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- struct rb_io_buffer *mask_buffer = NULL;
- TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
+ struct rb_io_buffer *mask_data = NULL;
+ TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_data);
- io_buffer_check_mask(mask_buffer);
+ io_buffer_check_mask(mask_data);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
- struct rb_io_buffer *output_buffer = NULL;
- TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
+ VALUE output = rb_io_buffer_new(NULL, data->size, io_flags_for_size(data->size));
+ struct rb_io_buffer *output_data = NULL;
+ TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_data);
- memory_or(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
+ memory_or(output_data->base, data->base, data->size, mask_data->base, mask_data->size);
return output;
}
@@ -3283,19 +2904,19 @@ memory_xor(unsigned char * restrict output, unsigned char * restrict base, size_
static VALUE
io_buffer_xor(VALUE self, VALUE mask)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- struct rb_io_buffer *mask_buffer = NULL;
- TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
+ struct rb_io_buffer *mask_data = NULL;
+ TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_data);
- io_buffer_check_mask(mask_buffer);
+ io_buffer_check_mask(mask_data);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
- struct rb_io_buffer *output_buffer = NULL;
- TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
+ VALUE output = rb_io_buffer_new(NULL, data->size, io_flags_for_size(data->size));
+ struct rb_io_buffer *output_data = NULL;
+ TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_data);
- memory_xor(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
+ memory_xor(output_data->base, data->base, data->size, mask_data->base, mask_data->size);
return output;
}
@@ -3323,14 +2944,14 @@ memory_not(unsigned char * restrict output, unsigned char * restrict base, size_
static VALUE
io_buffer_not(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
- struct rb_io_buffer *output_buffer = NULL;
- TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
+ VALUE output = rb_io_buffer_new(NULL, data->size, io_flags_for_size(data->size));
+ struct rb_io_buffer *output_data = NULL;
+ TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_data);
- memory_not(output_buffer->base, buffer->base, buffer->size);
+ memory_not(output_data->base, data->base, data->size);
return output;
}
@@ -3349,7 +2970,7 @@ static inline void
io_buffer_check_overlaps(struct rb_io_buffer *a, struct rb_io_buffer *b)
{
if (io_buffer_overlaps(a, b))
- rb_raise(rb_eIOBufferMaskError, "Mask overlaps source buffer!");
+ rb_raise(rb_eIOBufferMaskError, "Mask overlaps source data!");
}
static void
@@ -3380,20 +3001,20 @@ memory_and_inplace(unsigned char * restrict base, size_t size, unsigned char * r
static VALUE
io_buffer_and_inplace(VALUE self, VALUE mask)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- struct rb_io_buffer *mask_buffer = NULL;
- TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
+ struct rb_io_buffer *mask_data = NULL;
+ TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_data);
- io_buffer_check_mask(mask_buffer);
- io_buffer_check_overlaps(buffer, mask_buffer);
+ io_buffer_check_mask(mask_data);
+ io_buffer_check_overlaps(data, mask_data);
void *base;
size_t size;
- io_buffer_get_bytes_for_writing(buffer, &base, &size);
+ io_buffer_get_bytes_for_writing(data, &base, &size);
- memory_and_inplace(base, size, mask_buffer->base, mask_buffer->size);
+ memory_and_inplace(base, size, mask_data->base, mask_data->size);
return self;
}
@@ -3426,20 +3047,20 @@ memory_or_inplace(unsigned char * restrict base, size_t size, unsigned char * re
static VALUE
io_buffer_or_inplace(VALUE self, VALUE mask)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- struct rb_io_buffer *mask_buffer = NULL;
- TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
+ struct rb_io_buffer *mask_data = NULL;
+ TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_data);
- io_buffer_check_mask(mask_buffer);
- io_buffer_check_overlaps(buffer, mask_buffer);
+ io_buffer_check_mask(mask_data);
+ io_buffer_check_overlaps(data, mask_data);
void *base;
size_t size;
- io_buffer_get_bytes_for_writing(buffer, &base, &size);
+ io_buffer_get_bytes_for_writing(data, &base, &size);
- memory_or_inplace(base, size, mask_buffer->base, mask_buffer->size);
+ memory_or_inplace(base, size, mask_data->base, mask_data->size);
return self;
}
@@ -3472,20 +3093,20 @@ memory_xor_inplace(unsigned char * restrict base, size_t size, unsigned char * r
static VALUE
io_buffer_xor_inplace(VALUE self, VALUE mask)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
- struct rb_io_buffer *mask_buffer = NULL;
- TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
+ struct rb_io_buffer *mask_data = NULL;
+ TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_data);
- io_buffer_check_mask(mask_buffer);
- io_buffer_check_overlaps(buffer, mask_buffer);
+ io_buffer_check_mask(mask_data);
+ io_buffer_check_overlaps(data, mask_data);
void *base;
size_t size;
- io_buffer_get_bytes_for_writing(buffer, &base, &size);
+ io_buffer_get_bytes_for_writing(data, &base, &size);
- memory_xor_inplace(base, size, mask_buffer->base, mask_buffer->size);
+ memory_xor_inplace(base, size, mask_data->base, mask_data->size);
return self;
}
@@ -3518,12 +3139,12 @@ memory_not_inplace(unsigned char * restrict base, size_t size)
static VALUE
io_buffer_not_inplace(VALUE self)
{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+ struct rb_io_buffer *data = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);
void *base;
size_t size;
- io_buffer_get_bytes_for_writing(buffer, &base, &size);
+ io_buffer_get_bytes_for_writing(data, &base, &size);
memory_not_inplace(base, size);
@@ -3533,28 +3154,24 @@ io_buffer_not_inplace(VALUE self)
/*
* Document-class: IO::Buffer
*
- * IO::Buffer is a efficient zero-copy buffer for input/output. There are
- * typical use cases:
+ * IO::Buffer is a low-level efficient buffer for input/output. There are three
+ * ways of using buffer:
*
- * * Create an empty buffer with ::new, fill it with buffer using #copy or
- * #set_value, #set_string, get buffer with #get_string or write it directly
- * to some file with #write.
+ * * Create an empty buffer with ::new, fill it with data using #copy or
+ * #set_value, #set_string, get data with #get_string;
* * Create a buffer mapped to some string with ::for, then it could be used
* both for reading with #get_string or #get_value, and writing (writing will
- * change the source string, too).
+ * change the source string, too);
* * Create a buffer mapped to some file with ::map, then it could be used for
* reading and writing the underlying file.
- * * Create a string of a fixed size with ::string, then #read into it, or
- * modify it using #set_value.
*
* Interaction with string and file memory is performed by efficient low-level
* C mechanisms like `memcpy`.
*
* The class is meant to be an utility for implementing more high-level mechanisms
- * like Fiber::Scheduler#io_read and Fiber::Scheduler#io_write and parsing binary
- * protocols.
+ * like Fiber::SchedulerInterface#io_read and Fiber::SchedulerInterface#io_write.
*
- * == Examples of Usage
+ * <b>Examples of usage:</b>
*
* Empty buffer:
*
@@ -3573,7 +3190,7 @@ io_buffer_not_inplace(VALUE self)
*
* \Buffer from string:
*
- * string = 'buffer'
+ * string = 'data'
* buffer = IO::Buffer.for(string)
* # =>
* # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
@@ -3581,7 +3198,7 @@ io_buffer_not_inplace(VALUE self)
* buffer
* # =>
* # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
- * # 0x00000000 64 61 74 61 buffer
+ * # 0x00000000 64 61 74 61 data
*
* buffer.get_string(2) # read content starting from offset 2
* # => "ta"
@@ -3596,7 +3213,7 @@ io_buffer_not_inplace(VALUE self)
*
* \Buffer from file:
*
- * File.write('test.txt', 'test buffer')
+ * File.write('test.txt', 'test data')
* # => 9
* buffer = IO::Buffer.map(File.open('test.txt'))
* # =>
@@ -3613,35 +3230,22 @@ io_buffer_not_inplace(VALUE self)
* buffer.set_string('---', 1)
* # => 3 -- bytes written
* File.read('test.txt')
- * # => "t--- buffer"
+ * # => "t--- data"
*
- * <b>The class is experimental and the interface is subject to change, this
- * is especially true of file mappings which may be removed entirely in
- * the future.</b>
+ * <b>The class is experimental and the interface is subject to change.</b>
*/
void
Init_IO_Buffer(void)
{
rb_cIOBuffer = rb_define_class_under(rb_cIO, "Buffer", rb_cObject);
-
- /* Raised when an operation would resize or re-allocate a locked buffer. */
rb_eIOBufferLockedError = rb_define_class_under(rb_cIOBuffer, "LockedError", rb_eRuntimeError);
-
- /* Raised when the buffer cannot be allocated for some reason, or you try to use a buffer that's not allocated. */
rb_eIOBufferAllocationError = rb_define_class_under(rb_cIOBuffer, "AllocationError", rb_eRuntimeError);
-
- /* Raised when you try to write to a read-only buffer, or resize an external buffer. */
rb_eIOBufferAccessError = rb_define_class_under(rb_cIOBuffer, "AccessError", rb_eRuntimeError);
-
- /* Raised if you try to access a buffer slice which no longer references a valid memory range of the underlying source. */
rb_eIOBufferInvalidatedError = rb_define_class_under(rb_cIOBuffer, "InvalidatedError", rb_eRuntimeError);
-
- /* Raised if the mask given to a binary operation is invalid, e.g. zero length or overlaps the target buffer. */
rb_eIOBufferMaskError = rb_define_class_under(rb_cIOBuffer, "MaskError", rb_eArgError);
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;
@@ -3653,57 +3257,37 @@ Init_IO_Buffer(void)
RUBY_IO_BUFFER_DEFAULT_SIZE = io_buffer_default_size(RUBY_IO_BUFFER_PAGE_SIZE);
- /* The operating system page size. Used for efficient page-aligned memory allocations. */
+ // Efficient sizing of mapped buffers:
rb_define_const(rb_cIOBuffer, "PAGE_SIZE", SIZET2NUM(RUBY_IO_BUFFER_PAGE_SIZE));
-
- /* The default buffer size, typically a (small) multiple of the PAGE_SIZE.
- Can be explicitly specified by setting the RUBY_IO_BUFFER_DEFAULT_SIZE
- environment variable. */
rb_define_const(rb_cIOBuffer, "DEFAULT_SIZE", SIZET2NUM(RUBY_IO_BUFFER_DEFAULT_SIZE));
rb_define_singleton_method(rb_cIOBuffer, "map", io_buffer_map, -1);
+ // General use:
rb_define_method(rb_cIOBuffer, "initialize", rb_io_buffer_initialize, -1);
rb_define_method(rb_cIOBuffer, "initialize_copy", rb_io_buffer_initialize_copy, 1);
rb_define_method(rb_cIOBuffer, "inspect", rb_io_buffer_inspect, 0);
- rb_define_method(rb_cIOBuffer, "hexdump", rb_io_buffer_hexdump, -1);
+ rb_define_method(rb_cIOBuffer, "hexdump", rb_io_buffer_hexdump, 0);
rb_define_method(rb_cIOBuffer, "to_s", rb_io_buffer_to_s, 0);
rb_define_method(rb_cIOBuffer, "size", rb_io_buffer_size, 0);
rb_define_method(rb_cIOBuffer, "valid?", rb_io_buffer_valid_p, 0);
+ // Ownership:
rb_define_method(rb_cIOBuffer, "transfer", rb_io_buffer_transfer, 0);
- /* Indicates that the memory in the buffer is owned by someone else. See #external? for more details. */
+ // Flags:
rb_define_const(rb_cIOBuffer, "EXTERNAL", RB_INT2NUM(RB_IO_BUFFER_EXTERNAL));
-
- /* Indicates that the memory in the buffer is owned by the buffer. See #internal? for more details. */
rb_define_const(rb_cIOBuffer, "INTERNAL", RB_INT2NUM(RB_IO_BUFFER_INTERNAL));
-
- /* Indicates that the memory in the buffer is mapped by the operating system. See #mapped? for more details. */
rb_define_const(rb_cIOBuffer, "MAPPED", RB_INT2NUM(RB_IO_BUFFER_MAPPED));
-
- /* Indicates that the memory in the buffer is also mapped such that it can be shared with other processes. See #shared? for more details. */
rb_define_const(rb_cIOBuffer, "SHARED", RB_INT2NUM(RB_IO_BUFFER_SHARED));
-
- /* Indicates that the memory in the buffer is locked and cannot be resized or freed. See #locked? and #locked for more details. */
rb_define_const(rb_cIOBuffer, "LOCKED", RB_INT2NUM(RB_IO_BUFFER_LOCKED));
-
- /* Indicates that the memory in the buffer is mapped privately and changes won't be replicated to the underlying file. See #private? for more details. */
rb_define_const(rb_cIOBuffer, "PRIVATE", RB_INT2NUM(RB_IO_BUFFER_PRIVATE));
-
- /* Indicates that the memory in the buffer is read only, and attempts to modify it will fail. See #readonly? for more details.*/
rb_define_const(rb_cIOBuffer, "READONLY", RB_INT2NUM(RB_IO_BUFFER_READONLY));
- /* Refers to little endian byte order, where the least significant byte is stored first. See #get_value for more details. */
+ // Endian:
rb_define_const(rb_cIOBuffer, "LITTLE_ENDIAN", RB_INT2NUM(RB_IO_BUFFER_LITTLE_ENDIAN));
-
- /* Refers to big endian byte order, where the most significant byte is stored first. See #get_value for more details. */
rb_define_const(rb_cIOBuffer, "BIG_ENDIAN", RB_INT2NUM(RB_IO_BUFFER_BIG_ENDIAN));
-
- /* Refers to the byte order of the host machine. See #get_value for more details. */
rb_define_const(rb_cIOBuffer, "HOST_ENDIAN", RB_INT2NUM(RB_IO_BUFFER_HOST_ENDIAN));
-
- /* Refers to network byte order, which is the same as big endian. See #get_value for more details. */
rb_define_const(rb_cIOBuffer, "NETWORK_ENDIAN", RB_INT2NUM(RB_IO_BUFFER_NETWORK_ENDIAN));
rb_define_method(rb_cIOBuffer, "null?", rb_io_buffer_null_p, 0);
@@ -3713,7 +3297,6 @@ Init_IO_Buffer(void)
rb_define_method(rb_cIOBuffer, "mapped?", rb_io_buffer_mapped_p, 0);
rb_define_method(rb_cIOBuffer, "shared?", rb_io_buffer_shared_p, 0);
rb_define_method(rb_cIOBuffer, "locked?", rb_io_buffer_locked_p, 0);
- rb_define_method(rb_cIOBuffer, "private?", rb_io_buffer_private_p, 0);
rb_define_method(rb_cIOBuffer, "readonly?", io_buffer_readonly_p, 0);
// Locking to prevent changes while using pointer:
@@ -3771,7 +3354,7 @@ Init_IO_Buffer(void)
rb_define_method(rb_cIOBuffer, "get_string", io_buffer_get_string, -1);
rb_define_method(rb_cIOBuffer, "set_string", io_buffer_set_string, -1);
- // Binary buffer manipulations:
+ // Binary data manipulations:
rb_define_method(rb_cIOBuffer, "&", io_buffer_and, 1);
rb_define_method(rb_cIOBuffer, "|", io_buffer_or, 1);
rb_define_method(rb_cIOBuffer, "^", io_buffer_xor, 1);
diff --git a/iseq.c b/iseq.c
index 3bdb1c0af5..a6ba5c12bb 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"
@@ -113,9 +113,7 @@ 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 &&
- // See comment in vm_track_constant_cache on why we need this check
- id != vm->inserting_constant_cache_id) {
+ if (ics->num_entries == 0) {
rb_id_table_delete(vm->constant_cache, id);
st_free_table(ics);
}
@@ -166,19 +164,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);
- if (FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED)) {
- 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);
@@ -193,11 +187,7 @@ rb_iseq_free(const rb_iseq_t *iseq)
ruby_xfree((void *)body->mark_bits.list);
}
- ruby_xfree(body->variable.original_iseq);
-
if (body->param.keyword != NULL) {
- if (body->param.keyword->table != &body->local_table[body->param.keyword->bits_start - body->param.keyword->num])
- ruby_xfree((void *)body->param.keyword->table);
ruby_xfree((void *)body->param.keyword->default_values);
ruby_xfree((void *)body->param.keyword);
}
@@ -216,7 +206,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);
@@ -224,17 +214,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;
@@ -255,7 +248,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;
+ }
}
}
@@ -263,7 +259,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;
+ }
}
}
@@ -271,7 +270,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;
+ }
}
}
}
@@ -279,141 +281,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)
+{
+ return rb_gc_location(obj);
+}
+
+void
+rb_iseq_update_references(rb_iseq_t *iseq)
{
- if (cc) {
- if (reference_updating) {
- cc = (const struct rb_callcache *)rb_gc_location((VALUE)cc);
+ 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 (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);
+ if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
+ int i, j;
+
+ 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;
+ 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 (cds[i].ci) rb_gc_mark_and_move_ptr(&cds[i].ci);
-
- 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;
- for (int j = 0, i = keyword->required_num; i < keyword->num; i++, j++) {
- rb_gc_mark_and_move(&keyword->default_values[j]);
+ i = keyword->required_num;
+
+ 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);
- if (!reference_updating) {
- /* The operands in each instruction needs to be pinned because
- * if auto-compaction runs in iseq_set_sequence, then the objects
- * could exist on the generated_iseq buffer, which would not be
- * reference updated which can lead to T_MOVED (and subsequently
- * T_NONE) objects on the iseq. */
- rb_iseq_mark_and_pin_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);
}
}
@@ -533,19 +591,6 @@ 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)
{
@@ -743,6 +788,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 */
@@ -759,7 +805,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);
@@ -768,6 +814,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);
@@ -776,15 +823,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
@@ -825,6 +868,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);
@@ -879,7 +923,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);
}
}
@@ -940,11 +984,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;
@@ -956,7 +1002,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);
@@ -964,46 +1010,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);
-
-/**
- * Initialize an rb_code_location_t with a prism location.
- */
-static void
-pm_code_location(rb_code_location_t *code_location, const pm_newline_list_t *newline_list, const pm_location_t *location)
-{
- pm_line_column_t start = pm_newline_list_line_column(newline_list, location->start);
- pm_line_column_t end = pm_newline_list_line_column(newline_list, location->end);
-
- *code_location = (rb_code_location_t) {
- .beg_pos = { .lineno = (int) start.line, .column = (int) start.column },
- .end_pos = { .lineno = (int) end.line, .column = (int) end.column }
- };
-}
-
-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;
- if (!option) option = &COMPILE_OPTION_DEFAULT;
-
- rb_code_location_t code_location;
- pm_code_location(&code_location, &parser->newline_list, &scope_node->base.location);
-
- // TODO: node_id
- int node_id = -1;
- prepare_iseq_build(iseq, name, path, realpath, first_lineno, &code_location, 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,
@@ -1185,7 +1191,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);
}
@@ -1358,8 +1363,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
@@ -1381,10 +1386,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>
@@ -1393,7 +1394,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);
@@ -1415,125 +1416,6 @@ iseqw_s_compile(int argc, VALUE *argv, VALUE self)
return iseqw_new(rb_iseq_compile_with_option(src, file, path, line, opt));
}
-static void
-iseqw_s_compile_prism_compile(pm_parser_t *parser, VALUE opt, rb_iseq_t *iseq, VALUE file, VALUE path, int first_lineno)
-{
- pm_node_t *node = pm_parse(parser);
- rb_code_location_t code_location;
- pm_code_location(&code_location, &parser->newline_list, &node->location);
-
- rb_compile_option_t option;
- make_compile_option(&option, opt);
- prepare_iseq_build(iseq, rb_fstring_lit("<compiled>"), file, path, first_lineno, &code_location, -1, NULL, 0, ISEQ_TYPE_TOP, 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);
-}
-
-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);
-
- pm_options_t options = { 0 };
- pm_options_filepath_set(&options, RSTRING_PTR(file));
-
- int start_line = NUM2INT(line);
- pm_options_line_set(&options, start_line);
-
- pm_parser_t parser;
-
- if (RB_TYPE_P(src, T_FILE)) {
- FilePathValue(src);
- file = rb_fstring(src); /* rb_io_t->pathv gets frozen anyways */
-
- pm_string_t input;
- pm_string_mapped_init(&input, RSTRING_PTR(file));
-
- pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), &options);
- }
- else {
- pm_parser_init(&parser, (const uint8_t *) RSTRING_PTR(src), RSTRING_LEN(src), &options);
- }
-
- rb_iseq_t *iseq = iseq_alloc();
- iseqw_s_compile_prism_compile(&parser, opt, iseq, file, path, start_line);
- pm_parser_free(&parser);
- pm_options_free(&options);
-
- return iseqw_new(iseq);
-}
-
-static VALUE
-iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
-{
- VALUE file = Qnil, opt = Qnil;
- int i;
-
- i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
- if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 5);
- switch (i) {
- case 2: opt = argv[--i];
- }
- FilePathValue(file);
- file = rb_fstring(file); /* rb_io_t->pathv gets frozen anyways */
-
- pm_string_t input;
- pm_string_mapped_init(&input, RSTRING_PTR(file));
-
- pm_options_t options = { 0 };
- pm_options_filepath_set(&options, RSTRING_PTR(file));
-
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), &options);
-
- rb_iseq_t *iseq = iseq_alloc();
- iseqw_s_compile_prism_compile(&parser, opt, iseq, file, rb_realpath_internal(Qnil, file, 1), 1);
- pm_parser_free(&parser);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return iseqw_new(iseq);
-}
-
-rb_iseq_t *
-rb_iseq_new_main_prism(pm_string_t *input, pm_options_t *options, VALUE path)
-{
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
-
- if (NIL_P(path)) path = rb_fstring_lit("<compiled>");
- int start_line = 0;
- pm_options_line_set(options, start_line);
-
- rb_iseq_t *iseq = iseq_alloc();
- iseqw_s_compile_prism_compile(&parser, Qnil, iseq, path, path, start_line);
-
- pm_parser_free(&parser);
- return iseq;
-}
-
/*
* call-seq:
* InstructionSequence.compile_file(file[, options]) -> iseq
@@ -1622,6 +1504,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.
@@ -1685,11 +1568,7 @@ rb_iseqw_to_iseq(VALUE iseqw)
static VALUE
iseqw_eval(VALUE 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);
+ return rb_iseq_eval(iseqw_check(self));
}
/*
@@ -2111,7 +1990,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);
@@ -2153,7 +2032,7 @@ local_var_name(const rb_iseq_t *diseq, VALUE level, VALUE op)
if (!name) {
name = rb_str_new_cstr("?");
}
- else if (!rb_is_local_id(lid)) {
+ else if (!rb_str_symname_p(name)) {
name = rb_str_inspect(name);
}
else {
@@ -2307,6 +2186,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);
@@ -2410,7 +2290,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" : "",
@@ -2420,7 +2300,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" : "");
}
@@ -2510,6 +2389,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);
@@ -2765,7 +2645,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
}
@@ -2909,6 +2788,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)
{
@@ -3283,7 +3173,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;
}
@@ -3472,12 +3361,6 @@ typedef struct insn_data_struct {
static insn_data_t insn_data[VM_INSTRUCTION_SIZE/2];
void
-rb_free_encoded_insn_data(void)
-{
- st_free_table(encoded_insn_data);
-}
-
-void
rb_vm_encoded_insn_data_table_init(void)
{
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
@@ -3749,32 +3632,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)
{
@@ -3782,35 +3642,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
@@ -3826,9 +3671,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);
@@ -4043,7 +3887,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.
*
@@ -4116,8 +3960,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, "compile_file_prism", iseqw_s_compile_file_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 478f02afaf..e5ab4870e8 100644
--- a/iseq.h
+++ b/iseq.h
@@ -11,9 +11,7 @@
**********************************************************************/
#include "internal/gc.h"
-#include "shape.h"
#include "vm_core.h"
-#include "prism_compile.h"
RUBY_EXTERN const int ruby_api_version[];
#define ISEQ_MAJOR_VERSION ((unsigned int)ruby_api_version[0])
@@ -84,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)
@@ -117,7 +114,6 @@ 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;
@@ -129,7 +125,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
@@ -175,7 +170,6 @@ void rb_iseq_init_trace(rb_iseq_t *iseq);
int rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line, bool target_bmethod);
int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval);
const rb_iseq_t *rb_iseq_load_iseq(VALUE fname);
-rb_iseq_t * rb_iseq_new_main_prism(pm_string_t *input, pm_options_t *options, VALUE path);
#if VM_INSN_INFO_TABLE_IMPL == 2
unsigned int *rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body);
@@ -192,7 +186,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_pin_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);
@@ -230,6 +224,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;
@@ -275,11 +270,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)
@@ -330,10 +324,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);
-
-void rb_free_encoded_insn_data(void);
-
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 312085c289..2af01d2eae 100644
--- a/lib/abbrev.rb
+++ b/lib/abbrev.rb
@@ -47,7 +47,6 @@
# "w" => "winter" }
module Abbrev
- VERSION = "0.1.2"
# 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 0a96b44965..0000000000
--- a/lib/bundled_gems.rb
+++ /dev/null
@@ -1,242 +0,0 @@
-# -*- frozen-string-literal: true -*-
-
-# :stopdoc:
-
-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",
- "racc" => "3.3.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",
- "resolv-replace" => "3.4.0",
- "rinda" => "3.4.0",
- "syslog" => "3.4.0",
- }.freeze
-
- SINCE_FAST_PATH = SINCE.transform_keys { |g| g.sub(/\A.*\-/, "") }.freeze
-
- EXACT = {
- "kconv" => "nkf",
- }.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.replace_require(specs)
- return if [::Kernel.singleton_class, ::Kernel].any? {|klass| klass.respond_to?(:no_warning_require) }
-
- spec_names = specs.to_a.each_with_object({}) {|spec, h| h[spec.name] = true }
-
- [::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: spec_names)
- if ::Gem::BUNDLED_GEMS.uplevel > 0
- Kernel.warn message, uplevel: ::Gem::BUNDLED_GEMS.uplevel
- else
- Kernel.warn message
- end
- 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 self.uplevel
- frame_count = 0
- frames_to_skip = 3
- uplevel = 0
- require_found = false
- Thread.each_caller_location do |cl|
- frame_count += 1
- if frames_to_skip >= 1
- frames_to_skip -= 1
- next
- end
- uplevel += 1
- if require_found
- if cl.base_label != "require"
- return uplevel
- end
- else
- if cl.base_label == "require"
- require_found = true
- end
- end
- # Don't show script name when bundle exec and call ruby script directly.
- if cl.path.end_with?("bundle")
- frame_count = 0
- break
- end
- end
- require_found ? 1 : frame_count - 1
- end
-
- 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] || !!SINCE[n]) or PREFIXED[n = n[%r[\A[^/]+(?=/)]]] && n
- end
-
- def self.warning?(name, specs: nil)
- # name can be a feature name or a file path with String or Pathname
- feature = File.path(name)
-
- # The actual checks needed to properly identify the gem being required
- # are costly (see [Bug #20641]), so we first do a much cheaper check
- # to exclude the vast majority of candidates.
- if feature.include?("/")
- # If requiring $LIBDIR/mutex_m.rb, we check SINCE_FAST_PATH["mutex_m"]
- # We'll fail to warn requires for files that are not the entry point
- # of the gem, e.g. require "logger/formatter.rb" won't warn.
- # But that's acceptable because this warning is best effort,
- # and in the overwhelming majority of cases logger.rb will end
- # up required.
- return unless SINCE_FAST_PATH[File.basename(feature, ".*")]
- else
- return unless SINCE_FAST_PATH[feature]
- end
-
- # bootsnap expands `require "csv"` to `require "#{LIBDIR}/csv.rb"`,
- # and `require "syslog"` to `require "#{ARCHDIR}/syslog.so"`.
- name = feature.delete_prefix(ARCHDIR)
- name.delete_prefix!(LIBDIR)
- name.tr!("/", "-")
- name.sub!(LIBEXT, "")
- return if specs.include?(name)
- _t, path = $:.resolve_feature_path(feature)
- if gem = find_gem(path)
- return if specs.include?(gem)
- caller = caller_locations(3, 3)&.find {|c| c&.absolute_path}
- return if find_gem(caller&.absolute_path)
- elsif SINCE[name] && !path
- gem = true
- else
- return
- end
-
- return if WARNED[name]
- WARNED[name] = true
- if gem == true
- gem = name
- "#{feature} was loaded from the standard library, but"
- elsif gem
- return if WARNED[gem]
- WARNED[gem] = true
- "#{feature} is found in #{gem}, which"
- else
- return
- end + build_message(gem)
- end
-
- def self.build_message(gem)
- msg = " #{RUBY_VERSION < SINCE[gem] ? "will no longer be" : "is not"} part of the default gems starting from Ruby #{SINCE[gem]}."
-
- if defined?(Bundler)
- msg += "\nYou can add #{gem} to your Gemfile or gemspec to silence this warning."
-
- # We detect the gem name from caller_locations. First we walk until we find `require`
- # then take the first frame that's not from `require`.
- #
- # Additionally, we need to skip Bootsnap and Zeitwerk if present, these
- # gems decorate Kernel#require, so they are not really the ones issuing
- # the require call users should be warned about. Those are upwards.
- frames_to_skip = 3
- location = nil
- require_found = false
- Thread.each_caller_location do |cl|
- if frames_to_skip >= 1
- frames_to_skip -= 1
- next
- end
-
- if require_found
- if cl.base_label != "require"
- location = cl.path
- break
- end
- else
- if cl.base_label == "require"
- require_found = true
- end
- end
- end
-
- if location && 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 += "\nAlso please contact the author of #{caller_gem} to request adding #{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
- return super unless path
-
- name = path.tr("/", "-")
- if !defined?(Bundler) && Gem::BUNDLED_GEMS::SINCE[name] && !Gem::BUNDLED_GEMS::WARNED[name]
- warn name + Gem::BUNDLED_GEMS.build_message(name), uplevel: Gem::BUNDLED_GEMS.uplevel
- end
- super
- end
-end
-
-# :startdoc:
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 85532f4ac2..c6a225977f 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -17,7 +17,7 @@ require_relative "bundler/build_metadata"
# Bundler provides a consistent environment for Ruby projects by
# tracking and installing the exact gems and versions that are needed.
#
-# Bundler is a part of Ruby's standard library.
+# Since Ruby 2.6, Bundler is a part of Ruby's standard library.
#
# Bundler is used by creating _gemfiles_ listing all the project dependencies
# and (optionally) their versions and then using
@@ -39,10 +39,16 @@ module Bundler
environment_preserver.replace_with_backup
SUDO_MUTEX = Thread::Mutex.new
- autoload :Checksum, File.expand_path("bundler/checksum", __dir__)
- autoload :CLI, File.expand_path("bundler/cli", __dir__)
- autoload :CIDetector, File.expand_path("bundler/ci_detector", __dir__)
- autoload :CompactIndexClient, File.expand_path("bundler/compact_index_client", __dir__)
+ SAFE_MARSHAL_CLASSES = [Symbol, TrueClass, String, Array, Hash].freeze
+ SAFE_MARSHAL_ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed.".freeze
+ SAFE_MARSHAL_PROC = proc do |object|
+ object.tap do
+ unless SAFE_MARSHAL_CLASSES.include?(object.class)
+ raise TypeError, format(SAFE_MARSHAL_ERROR, object.class, SAFE_MARSHAL_CLASSES.join(", "))
+ end
+ end
+ end
+
autoload :Definition, File.expand_path("bundler/definition", __dir__)
autoload :Dependency, File.expand_path("bundler/dependency", __dir__)
autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__)
@@ -79,12 +85,10 @@ module Bundler
autoload :StubSpecification, File.expand_path("bundler/stub_specification", __dir__)
autoload :UI, File.expand_path("bundler/ui", __dir__)
autoload :URICredentialsFilter, File.expand_path("bundler/uri_credentials_filter", __dir__)
- autoload :URINormalizer, File.expand_path("bundler/uri_normalizer", __dir__)
- autoload :SafeMarshal, File.expand_path("bundler/safe_marshal", __dir__)
class << self
def configure
- @configure ||= configure_gem_home_and_path
+ @configured ||= configure_gem_home_and_path
end
def ui
@@ -102,7 +106,9 @@ module Bundler
end
def create_bundle_path
- mkdir_p(bundle_path) unless bundle_path.exist?
+ SharedHelpers.filesystem_access(bundle_path.to_s) do |p|
+ mkdir_p(p)
+ end unless bundle_path.exist?
@bundle_path = bundle_path.realpath
rescue Errno::EEXIST
@@ -119,7 +125,7 @@ module Bundler
@bin_path ||= begin
path = settings[:bin] || "bin"
path = Pathname.new(path).expand_path(root).expand_path
- mkdir_p(path)
+ SharedHelpers.filesystem_access(path) {|p| FileUtils.mkdir_p(p) }
path
end
end
@@ -167,29 +173,6 @@ module Bundler
end
end
- def auto_switch
- self_manager.restart_with_locked_bundler_if_needed
- end
-
- # Automatically install dependencies if Bundler.settings[:auto_install] exists.
- # This is set through config cmd `bundle config set --global auto_install 1`.
- #
- # Note that this method `nil`s out the global Definition object, so it
- # should be called first, before you instantiate anything like an
- # `Installer` that'll keep a reference to the old one instead.
- def auto_install
- return unless settings[:auto_install]
-
- begin
- definition.specs
- rescue GemNotFound, GitError
- ui.info "Automatically installing missing gems."
- reset!
- CLI::Install.new({}).run
- reset!
- end
- end
-
# Setups Bundler environment (see Bundler.setup) if it is not already set,
# and loads all gems from groups specified. Unlike ::setup, can be called
# multiple times with different groups (if they were allowed by setup).
@@ -217,7 +200,7 @@ module Bundler
end
def environment
- SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", print_caller_location: true
+ SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", :print_caller_location => true
load
end
@@ -225,21 +208,19 @@ module Bundler
#
# @param unlock [Hash, Boolean, nil] Gems that have been requested
# to be updated or true if all gems should be updated
- # @param lockfile [Pathname] Path to Gemfile.lock
# @return [Bundler::Definition]
- def definition(unlock = nil, lockfile = default_lockfile)
+ def definition(unlock = nil)
@definition = nil if unlock
@definition ||= begin
configure
- Definition.build(default_gemfile, lockfile, unlock)
+ Definition.build(default_gemfile, default_lockfile, unlock)
end
end
def frozen_bundle?
- frozen = settings[:frozen]
- return frozen unless frozen.nil?
-
- settings[:deployment]
+ frozen = settings[:deployment]
+ frozen ||= settings[:frozen]
+ frozen
end
def locked_gems
@@ -356,12 +337,20 @@ 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
@settings ||= Settings.new(app_config_path)
rescue GemfileNotFound
- @settings = Settings.new
+ @settings = Settings.new(Pathname.new(".bundle").expand_path)
end
# @return [Hash] Environment present before Bundler was activated
@@ -371,24 +360,40 @@ module Bundler
# @deprecated Use `unbundled_env` instead
def clean_env
- message =
+ Bundler::SharedHelpers.major_deprecation(
+ 2,
"`Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \
- "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`"
- removed_message =
- "`Bundler.clean_env` has been removed in favor of `Bundler.unbundled_env`. " \
- "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`"
- Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`",
+ :print_caller_location => true
+ )
+
unbundled_env
end
# @return [Hash] Environment with all bundler-related variables removed
def unbundled_env
- unbundle_env(original_env)
- end
+ env = original_env
+
+ if env.key?("BUNDLER_ORIG_MANPATH")
+ env["MANPATH"] = env["BUNDLER_ORIG_MANPATH"]
+ end
+
+ env.delete_if {|k, _| k[0, 7] == "BUNDLE_" }
- # Remove all bundler-related variables from ENV
- def unbundle_env!
- ENV.replace(unbundle_env(ENV))
+ if env.key?("RUBYOPT")
+ rubyopt = env["RUBYOPT"].split(" ")
+ rubyopt.delete("-r#{File.expand_path("bundler/setup", __dir__)}")
+ rubyopt.delete("-rbundler/setup")
+ env["RUBYOPT"] = rubyopt.join(" ")
+ end
+
+ if env.key?("RUBYLIB")
+ rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR)
+ rubylib.delete(__dir__)
+ env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR)
+ end
+
+ env
end
# Run block with environment present before Bundler was activated
@@ -398,13 +403,13 @@ module Bundler
# @deprecated Use `with_unbundled_env` instead
def with_clean_env
- message =
+ Bundler::SharedHelpers.major_deprecation(
+ 2,
"`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \
- "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`"
- removed_message =
- "`Bundler.with_clean_env` has been removed in favor of `Bundler.with_unbundled_env`. " \
- "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`"
- Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`",
+ :print_caller_location => true
+ )
+
with_env(unbundled_env) { yield }
end
@@ -420,13 +425,13 @@ module Bundler
# @deprecated Use `unbundled_system` instead
def clean_system(*args)
- message =
+ Bundler::SharedHelpers.major_deprecation(
+ 2,
"`Bundler.clean_system` has been deprecated in favor of `Bundler.unbundled_system`. " \
- "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`"
- removed_message =
- "`Bundler.clean_system` has been removed in favor of `Bundler.unbundled_system`. " \
- "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`"
- Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`",
+ :print_caller_location => true
+ )
+
with_env(unbundled_env) { Kernel.system(*args) }
end
@@ -442,13 +447,13 @@ module Bundler
# @deprecated Use `unbundled_exec` instead
def clean_exec(*args)
- message =
+ Bundler::SharedHelpers.major_deprecation(
+ 2,
"`Bundler.clean_exec` has been deprecated in favor of `Bundler.unbundled_exec`. " \
- "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`"
- removed_message =
- "`Bundler.clean_exec` has been removed in favor of `Bundler.unbundled_exec`. " \
- "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`"
- Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`",
+ :print_caller_location => true
+ )
+
with_env(unbundled_env) { Kernel.exec(*args) }
end
@@ -491,7 +496,7 @@ module Bundler
configured_bundle_path.use_system_gems?
end
- def mkdir_p(path)
+ def mkdir_p(path, options = {})
SharedHelpers.filesystem_access(path, :write) do |p|
FileUtils.mkdir_p(p)
end
@@ -501,7 +506,7 @@ module Bundler
if File.file?(executable) && File.executable?(executable)
executable
elsif paths = ENV["PATH"]
- quote = '"'
+ quote = '"'.freeze
paths.split(File::PATH_SEPARATOR).find do |path|
path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote)
executable_path = File.expand_path(executable, path)
@@ -517,16 +522,13 @@ 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 => SAFE_MARSHAL_PROC)
+ end
+
+ def load_marshal(data, marshal_proc: nil)
+ Marshal.load(data, marshal_proc)
+ rescue TypeError => e
+ raise MarshalError, "#{e.class}: #{e.message}"
end
def load_gemspec(file, validate = false)
@@ -535,7 +537,7 @@ module Bundler
@gemspec_cache[key] ||= load_gemspec_uncached(file, validate)
# Protect against caching side-effected gemspecs by returning a
# new instance each time.
- @gemspec_cache[key]&.dup
+ @gemspec_cache[key].dup if @gemspec_cache[key]
end
def load_gemspec_uncached(file, validate = false)
@@ -584,7 +586,7 @@ module Bundler
@bin_path = nil
@bundler_major_version = nil
@bundle_path = nil
- @configure = nil
+ @configured = nil
@configured_bundle_path = nil
@definition = nil
@load = nil
@@ -617,36 +619,6 @@ module Bundler
private
- def unbundle_env(env)
- if env.key?("BUNDLER_ORIG_MANPATH")
- env["MANPATH"] = env["BUNDLER_ORIG_MANPATH"]
- end
-
- env.delete_if {|k, _| k[0, 7] == "BUNDLE_" }
- env.delete("BUNDLER_SETUP")
-
- if env.key?("RUBYOPT")
- rubyopt = env["RUBYOPT"].split(" ")
- rubyopt.delete("-r#{File.expand_path("bundler/setup", __dir__)}")
- rubyopt.delete("-rbundler/setup")
- env["RUBYOPT"] = rubyopt.join(" ")
- end
-
- if env.key?("RUBYLIB")
- rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR)
- rubylib.delete(__dir__)
- env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR)
- end
-
- env
- end
-
- def load_marshal(data, marshal_proc: nil)
- Marshal.load(data, marshal_proc)
- rescue TypeError => e
- raise MarshalError, "#{e.class}: #{e.message}"
- end
-
def eval_yaml_gemspec(path, contents)
Kernel.require "psych"
@@ -660,7 +632,7 @@ module Bundler
rescue ScriptError, StandardError => e
msg = "There was an error while loading `#{path.basename}`: #{e.message}"
- raise GemspecError, Dsl::DSLError.new(msg, path.to_s, e.backtrace, contents)
+ raise GemspecError, Dsl::DSLError.new(msg, path, e.backtrace, contents)
end
def configure_gem_path
diff --git a/lib/bundler/build_metadata.rb b/lib/bundler/build_metadata.rb
index 5d2a8b53bb..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/bundler.gemspec b/lib/bundler/bundler.gemspec
index 2d6269fae1..da50b46225 100644
--- a/lib/bundler/bundler.gemspec
+++ b/lib/bundler/bundler.gemspec
@@ -29,17 +29,15 @@ Gem::Specification.new do |s|
"source_code_uri" => "https://github.com/rubygems/rubygems/tree/master/bundler",
}
- s.required_ruby_version = ">= 3.0.0"
-
- # It should match the RubyGems version shipped with `required_ruby_version` above
- s.required_rubygems_version = ">= 3.2.3"
+ s.required_ruby_version = ">= 2.6.0"
+ s.required_rubygems_version = ">= 3.0.1"
s.files = Dir.glob("lib/bundler{.rb,/**/*}", File::FNM_DOTMATCH).reject {|f| File.directory?(f) }
# include the gemspec itself because warbler breaks w/o it
s.files += %w[lib/bundler/bundler.gemspec]
- s.bindir = "exe"
+ s.bindir = "libexec"
s.executables = %w[bundle bundler]
s.require_paths = ["lib"]
end
diff --git a/lib/bundler/capistrano.rb b/lib/bundler/capistrano.rb
index 705840143f..1f3712d48e 100644
--- a/lib/bundler/capistrano.rb
+++ b/lib/bundler/capistrano.rb
@@ -17,6 +17,6 @@ end
Capistrano::Configuration.instance(:must_exist).load do
before "deploy:finalize_update", "bundle:install"
- Bundler::Deployment.define_task(self, :task, except: { no_release: true })
+ Bundler::Deployment.define_task(self, :task, :except => { :no_release => true })
set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" }
end
diff --git a/lib/bundler/checksum.rb b/lib/bundler/checksum.rb
deleted file mode 100644
index 60ba93417c..0000000000
--- a/lib/bundler/checksum.rb
+++ /dev/null
@@ -1,254 +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_package(gem_package, algo = DEFAULT_ALGORITHM)
- return if Bundler.settings[:disable_checksum_validation]
- return unless source = gem_package.instance_variable_get(:@gem)
- return unless source.respond_to?(:with_read_io)
-
- source.with_read_io do |io|
- from_gem(io, source.path)
- ensure
- io.rewind
- end
- end
-
- 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)
- return if Bundler.settings[:disable_checksum_validation]
-
- 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
- digest.unpack1("m0").unpack1("H*")
- else
- raise ArgumentError, "#{digest.inspect} is not a valid SHA256 hex or base64 digest"
- end
- 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 same_source?(other)
- sources.include?(other.sources.first)
- end
-
- 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 = {}
- @store_mutex = Mutex.new
- end
-
- def inspect
- "#<#{self.class}:#{object_id} size=#{store.size}>"
- end
-
- # Replace when the new checksum is from the same source.
- # The primary purpose is 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 unless checksum
-
- lock_name = spec.name_tuple.lock_name
- @store_mutex.synchronize do
- existing = fetch_checksum(lock_name, checksum.algo)
- if !existing || existing.same_source?(checksum)
- store_checksum(lock_name, checksum)
- else
- merge_checksum(lock_name, checksum, existing)
- end
- end
- end
-
- def register(spec, checksum)
- return unless checksum
-
- register_checksum(spec.name_tuple.lock_name, checksum)
- end
-
- def merge!(other)
- other.store.each do |lock_name, checksums|
- checksums.each do |_algo, checksum|
- register_checksum(lock_name, checksum)
- end
- end
- end
-
- def to_lock(spec)
- lock_name = spec.name_tuple.lock_name
- checksums = @store[lock_name]
- if checksums
- "#{lock_name} #{checksums.values.map(&:to_lock).sort.join(",")}"
- else
- lock_name
- end
- end
-
- private
-
- def register_checksum(lock_name, checksum)
- @store_mutex.synchronize do
- existing = fetch_checksum(lock_name, checksum.algo)
- if existing
- merge_checksum(lock_name, checksum, existing)
- else
- store_checksum(lock_name, checksum)
- end
- end
- end
-
- def merge_checksum(lock_name, checksum, existing)
- existing.merge!(checksum) || raise(ChecksumMismatchError.new(lock_name, existing, checksum))
- end
-
- def store_checksum(lock_name, checksum)
- (@store[lock_name] ||= {})[checksum.algo] = checksum
- end
-
- def fetch_checksum(lock_name, algo)
- @store[lock_name]&.fetch(algo, nil)
- end
- end
- end
-end
diff --git a/lib/bundler/ci_detector.rb b/lib/bundler/ci_detector.rb
deleted file mode 100644
index e5fedbdea8..0000000000
--- a/lib/bundler/ci_detector.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- module CIDetector
- # NOTE: Any changes made here will need to be made to both lib/rubygems/ci_detector.rb and
- # bundler/lib/bundler/ci_detector.rb (which are enforced duplicates).
- # TODO: Drop that duplication once bundler drops support for RubyGems 3.4
- #
- # ## Recognized CI providers, their signifiers, and the relevant docs ##
- #
- # Travis CI - CI, TRAVIS https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
- # Cirrus CI - CI, CIRRUS_CI https://cirrus-ci.org/guide/writing-tasks/#environment-variables
- # Circle CI - CI, CIRCLECI https://circleci.com/docs/variables/#built-in-environment-variables
- # Gitlab CI - CI, GITLAB_CI https://docs.gitlab.com/ee/ci/variables/
- # AppVeyor - CI, APPVEYOR https://www.appveyor.com/docs/environment-variables/
- # CodeShip - CI_NAME https://docs.cloudbees.com/docs/cloudbees-codeship/latest/pro-builds-and-configuration/environment-variables#_default_environment_variables
- # dsari - CI, DSARI https://github.com/rfinnie/dsari#running
- # Jenkins - BUILD_NUMBER https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
- # TeamCity - TEAMCITY_VERSION https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters
- # Appflow - CI_BUILD_ID https://ionic.io/docs/appflow/automation/environments#predefined-environments
- # TaskCluster - TASKCLUSTER_ROOT_URL https://docs.taskcluster.net/docs/manual/design/env-vars
- # Semaphore - CI, SEMAPHORE https://docs.semaphoreci.com/ci-cd-environment/environment-variables/
- # BuildKite - CI, BUILDKITE https://buildkite.com/docs/pipelines/environment-variables
- # GoCD - GO_SERVER_URL https://docs.gocd.org/current/faq/dev_use_current_revision_in_build.html
- # GH Actions - CI, GITHUB_ACTIONS https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
- #
- # ### Some "standard" ENVs that multiple providers may set ###
- #
- # * CI - this is set by _most_ (but not all) CI providers now; it's approaching a standard.
- # * CI_NAME - Not as frequently used, but some providers set this to specify their own name
-
- # Any of these being set is a reasonably reliable indicator that we are
- # executing in a CI environment.
- ENV_INDICATORS = [
- "CI",
- "CI_NAME",
- "CONTINUOUS_INTEGRATION",
- "BUILD_NUMBER",
- "CI_APP_ID",
- "CI_BUILD_ID",
- "CI_BUILD_NUMBER",
- "RUN_ID",
- "TASKCLUSTER_ROOT_URL",
- ].freeze
-
- # For each CI, this env suffices to indicate that we're on _that_ CI's
- # containers. (A few of them only supply a CI_NAME variable, which is also
- # nice). And if they set "CI" but we can't tell which one they are, we also
- # want to know that - a bare "ci" without another token tells us as much.
- ENV_DESCRIPTORS = {
- "TRAVIS" => "travis",
- "CIRCLECI" => "circle",
- "CIRRUS_CI" => "cirrus",
- "DSARI" => "dsari",
- "SEMAPHORE" => "semaphore",
- "JENKINS_URL" => "jenkins",
- "BUILDKITE" => "buildkite",
- "GO_SERVER_URL" => "go",
- "GITLAB_CI" => "gitlab",
- "GITHUB_ACTIONS" => "github",
- "TASKCLUSTER_ROOT_URL" => "taskcluster",
- "CI" => "ci",
- }.freeze
-
- def self.ci?
- ENV_INDICATORS.any? {|var| ENV.include?(var) }
- end
-
- def self.ci_strings
- matching_names = ENV_DESCRIPTORS.select {|env, _| ENV[env] }.values
- matching_names << ENV["CI_NAME"].downcase if ENV["CI_NAME"]
- matching_names.reject(&:empty?).sort.uniq
- end
- end
-end
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index 743f32d014..ee73bdb506 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -5,7 +5,6 @@ require_relative "vendored_thor"
module Bundler
class CLI < Thor
require_relative "cli/common"
- require_relative "cli/install"
package_name "Bundler"
@@ -65,12 +64,12 @@ module Bundler
Bundler.reset_settings_and_root!
end
- Bundler.auto_switch
+ Bundler.self_manager.restart_with_locked_bundler_if_needed
Bundler.settings.set_command_option_if_given :retry, options[:retry]
current_cmd = args.last[:current_command].name
- Bundler.auto_install if AUTO_INSTALL_CMDS.include?(current_cmd)
+ auto_install if AUTO_INSTALL_CMDS.include?(current_cmd)
rescue UnknownArgumentError => e
raise InvalidOption, e.message
ensure
@@ -81,10 +80,10 @@ module Bundler
unprinted_warnings.each {|w| Bundler.ui.warn(w) }
end
- check_unknown_options!(except: [:config, :exec])
+ check_unknown_options!(:except => [:config, :exec])
stop_on_unknown_option! :exec
- desc "cli_help", "Prints a summary of bundler commands", hide: true
+ desc "cli_help", "Prints a summary of bundler commands", :hide => true
def cli_help
version
Bundler.ui.info "\n"
@@ -100,23 +99,21 @@ module Bundler
shell.say "Bundler commands:\n\n"
shell.say " Primary commands:\n"
- shell.print_table(primary_commands, indent: 4, truncate: true)
+ shell.print_table(primary_commands, :indent => 4, :truncate => true)
shell.say
shell.say " Utilities:\n"
- shell.print_table(utilities, indent: 4, truncate: true)
+ shell.print_table(utilities, :indent => 4, :truncate => true)
shell.say
self.class.send(:class_options_help, shell)
end
default_task(Bundler.feature_flag.default_cli_command)
- class_option "no-color", type: :boolean, desc: "Disable colorization in output"
- class_option "retry", type: :numeric, aliases: "-r", banner: "NUM",
- desc: "Specify the number of times you wish to attempt network commands"
- class_option "verbose", type: :boolean, desc: "Enable verbose output mode", aliases: "-V"
+ class_option "no-color", :type => :boolean, :desc => "Disable colorization in output"
+ class_option "retry", :type => :numeric, :aliases => "-r", :banner => "NUM",
+ :desc => "Specify the number of times you wish to attempt network commands"
+ class_option "verbose", :type => :boolean, :desc => "Enable verbose output mode", :aliases => "-V"
def help(cli = nil)
- cli = self.class.all_aliases[cli] if self.class.all_aliases[cli]
-
case cli
when "gemfile" then command = "gemfile"
when nil then command = "bundle"
@@ -130,8 +127,8 @@ module Bundler
if man_pages.include?(command)
man_page = man_pages[command]
- if Bundler.which("man") && !man_path.match?(%r{^file:/.+!/META-INF/jruby.home/.+})
- Kernel.exec("man", man_page)
+ if Bundler.which("man") && man_path !~ %r{^file:/.+!/META-INF/jruby.home/.+}
+ Kernel.exec "man #{man_page}"
else
puts File.read("#{man_path}/#{File.basename(man_page)}.ronn")
end
@@ -158,8 +155,7 @@ module Bundler
Gemfile to a gem with a gemspec, the --gemspec option will automatically add each
dependency listed in the gemspec file to the newly created Gemfile.
D
- method_option "gemspec", type: :string, banner: "Use the specified .gemspec to create the Gemfile"
- method_option "gemfile", type: :string, banner: "Use the specified name for the gemfile instead of 'Gemfile'"
+ method_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile"
def init
require_relative "cli/init"
Init.new(options.dup).run
@@ -171,9 +167,12 @@ module Bundler
all gems are found, Bundler prints a success message and exits with a status of 0.
If not, the first missing gem is listed and Bundler exits status 1.
D
- method_option "dry-run", type: :boolean, default: false, banner: "Lock the Gemfile"
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "path", type: :string, banner: "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
+ method_option "dry-run", :type => :boolean, :default => false, :banner =>
+ "Lock the Gemfile"
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "path", :type => :string, :banner =>
+ "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
def check
remembered_flag_deprecation("path")
@@ -187,14 +186,10 @@ module Bundler
long_desc <<-D
Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If the gem is not found, Bundler prints a error message and if gem could not be removed due to any reason Bundler will display a warning.
D
- method_option "install", type: :boolean, banner: "Runs 'bundle install' after removing the gems from the Gemfile"
+ method_option "install", :type => :boolean, :banner =>
+ "Runs 'bundle install' after removing the gems from the Gemfile"
def remove(*gems)
- if ARGV.include?("--install")
- message = "The `--install` flag has been deprecated. `bundle install` is triggered by default."
- removed_message = "The `--install` flag has been removed. `bundle install` is triggered by default."
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message)
- end
-
+ SharedHelpers.major_deprecation(2, "The `--install` flag has been deprecated. `bundle install` is triggered by default.") if ARGV.include?("--install")
require_relative "cli/remove"
Remove.new(gems, options).run
end
@@ -210,40 +205,58 @@ module Bundler
If the bundle has already been installed, bundler will tell you so and then exit.
D
- method_option "binstubs", type: :string, lazy_default: "bin", banner: "Generate bin stubs for bundled gems to ./bin"
- method_option "clean", type: :boolean, banner: "Run bundle clean automatically after install"
- method_option "deployment", type: :boolean, banner: "Install using defaults tuned for deployment environments"
- method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this install"
- method_option "full-index", type: :boolean, banner: "Fall back to using the single-file index of all gems"
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "jobs", aliases: "-j", type: :numeric, banner: "Specify the number of jobs to run in parallel"
- method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead"
- method_option "prefer-local", type: :boolean, banner: "Only attempt to fetch gems remotely if not present locally, even if newer versions are available remotely"
- method_option "no-cache", type: :boolean, banner: "Don't update the existing gem cache."
- method_option "redownload", type: :boolean, aliases: "--force", banner: "Force downloading every gem."
- method_option "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache."
- method_option "path", type: :string, banner: "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
- method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
- method_option "shebang", type: :string, banner: "Specify a different shebang executable name than the default (usually 'ruby')"
- method_option "standalone", type: :array, lazy_default: [], banner: "Make a bundle that can work without the Bundler runtime"
- method_option "system", type: :boolean, banner: "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application"
- method_option "trust-policy", alias: "P", type: :string, banner: "Gem trust policy (like gem install -P). Must be one of " +
- Bundler.rubygems.security_policy_keys.join("|")
- method_option "without", type: :array, banner: "Exclude gems that are part of the specified named group."
- method_option "with", type: :array, banner: "Include gems that are part of the specified named group."
+ method_option "binstubs", :type => :string, :lazy_default => "bin", :banner =>
+ "Generate bin stubs for bundled gems to ./bin"
+ method_option "clean", :type => :boolean, :banner =>
+ "Run bundle clean automatically after install"
+ method_option "deployment", :type => :boolean, :banner =>
+ "Install using defaults tuned for deployment environments"
+ method_option "frozen", :type => :boolean, :banner =>
+ "Do not allow the Gemfile.lock to be updated after this install"
+ method_option "full-index", :type => :boolean, :banner =>
+ "Fall back to using the single-file index of all gems"
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "jobs", :aliases => "-j", :type => :numeric, :banner =>
+ "Specify the number of jobs to run in parallel"
+ method_option "local", :type => :boolean, :banner =>
+ "Do not attempt to fetch gems remotely and use the gem cache instead"
+ method_option "prefer-local", :type => :boolean, :banner =>
+ "Only attempt to fetch gems remotely if not present locally, even if newer versions are available remotely"
+ method_option "no-cache", :type => :boolean, :banner =>
+ "Don't update the existing gem cache."
+ method_option "redownload", :type => :boolean, :aliases => "--force", :banner =>
+ "Force downloading every gem."
+ method_option "no-prune", :type => :boolean, :banner =>
+ "Don't remove stale gems from the cache."
+ method_option "path", :type => :string, :banner =>
+ "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
+ method_option "quiet", :type => :boolean, :banner =>
+ "Only output warnings and errors."
+ method_option "shebang", :type => :string, :banner =>
+ "Specify a different shebang executable name than the default (usually 'ruby')"
+ method_option "standalone", :type => :array, :lazy_default => [], :banner =>
+ "Make a bundle that can work without the Bundler runtime"
+ method_option "system", :type => :boolean, :banner =>
+ "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application"
+ method_option "trust-policy", :alias => "P", :type => :string, :banner =>
+ "Gem trust policy (like gem install -P). Must be one of " +
+ Bundler.rubygems.security_policy_keys.join("|")
+ method_option "without", :type => :array, :banner =>
+ "Exclude gems that are part of the specified named group."
+ method_option "with", :type => :array, :banner =>
+ "Include gems that are part of the specified named group."
def install
SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force")
- %w[clean deployment frozen no-prune path shebang without with].each do |option|
+ %w[clean deployment frozen no-prune path shebang system without with].each do |option|
remembered_flag_deprecation(option)
end
- print_remembered_flag_deprecation("--system", "path.system", "true") if ARGV.include?("--system")
-
remembered_negative_flag_deprecation("no-deployment")
require_relative "cli/install"
- Bundler.settings.temporary(no_install: false) do
+ Bundler.settings.temporary(:no_install => false) do
Install.new(options.dup).run
end
end
@@ -256,27 +269,44 @@ module Bundler
update when you have changed the Gemfile, or if you want to get the newest
possible versions of the gems in the bundle.
D
- method_option "full-index", type: :boolean, banner: "Fall back to using the single-file index of all gems"
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "group", aliases: "-g", type: :array, banner: "Update a specific group"
- method_option "jobs", aliases: "-j", type: :numeric, banner: "Specify the number of jobs to run in parallel"
- method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead"
- method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
- method_option "source", type: :array, banner: "Update a specific source (and all gems associated with it)"
- method_option "redownload", type: :boolean, aliases: "--force", banner: "Force downloading every gem."
- method_option "ruby", type: :boolean, banner: "Update ruby specified in Gemfile.lock"
- method_option "bundler", type: :string, lazy_default: "> 0.a", banner: "Update the locked version of bundler"
- method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version"
- method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version"
- method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)"
- method_option "pre", type: :boolean, banner: "Always choose the highest allowed version when updating gems, regardless of prerelease status"
- method_option "strict", type: :boolean, banner: "Do not allow any gem to be updated past latest --patch | --minor | --major"
- method_option "conservative", type: :boolean, banner: "Use bundle install conservative update behavior and do not allow shared dependencies to be updated."
- method_option "all", type: :boolean, banner: "Update everything."
+ method_option "full-index", :type => :boolean, :banner =>
+ "Fall back to using the single-file index of all gems"
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "group", :aliases => "-g", :type => :array, :banner =>
+ "Update a specific group"
+ method_option "jobs", :aliases => "-j", :type => :numeric, :banner =>
+ "Specify the number of jobs to run in parallel"
+ method_option "local", :type => :boolean, :banner =>
+ "Do not attempt to fetch gems remotely and use the gem cache instead"
+ method_option "quiet", :type => :boolean, :banner =>
+ "Only output warnings and errors."
+ method_option "source", :type => :array, :banner =>
+ "Update a specific source (and all gems associated with it)"
+ method_option "redownload", :type => :boolean, :aliases => "--force", :banner =>
+ "Force downloading every gem."
+ method_option "ruby", :type => :boolean, :banner =>
+ "Update ruby specified in Gemfile.lock"
+ method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner =>
+ "Update the locked version of bundler"
+ method_option "patch", :type => :boolean, :banner =>
+ "Prefer updating only to next patch version"
+ method_option "minor", :type => :boolean, :banner =>
+ "Prefer updating only to next minor version"
+ method_option "major", :type => :boolean, :banner =>
+ "Prefer updating to next major version (default)"
+ method_option "pre", :type => :boolean, :banner =>
+ "Always choose the highest allowed version when updating gems, regardless of prerelease status"
+ method_option "strict", :type => :boolean, :banner =>
+ "Do not allow any gem to be updated past latest --patch | --minor | --major"
+ method_option "conservative", :type => :boolean, :banner =>
+ "Use bundle install conservative update behavior and do not allow shared dependencies to be updated."
+ method_option "all", :type => :boolean, :banner =>
+ "Update everything."
def update(*gems)
SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force")
require_relative "cli/update"
- Bundler.settings.temporary(no_install: false) do
+ Bundler.settings.temporary(:no_install => false) do
Update.new(options, gems).run
end
end
@@ -286,25 +316,21 @@ module Bundler
Show lists the names and versions of all gems that are required by your Gemfile.
Calling show with [GEM] will list the exact location of that gem on your machine.
D
- method_option "paths", type: :boolean,
- banner: "List the paths of all gems that are required by your Gemfile."
- method_option "outdated", type: :boolean,
- banner: "Show verbose output including whether gems are outdated."
+ method_option "paths", :type => :boolean,
+ :banner => "List the paths of all gems that are required by your Gemfile."
+ method_option "outdated", :type => :boolean,
+ :banner => "Show verbose output including whether gems are outdated."
def show(gem_name = nil)
- if ARGV.include?("--outdated")
- message = "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement"
- removed_message = "the `--outdated` flag to `bundle show` was undocumented and has been removed without replacement"
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message)
- end
+ SharedHelpers.major_deprecation(2, "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement") if ARGV.include?("--outdated")
require_relative "cli/show"
Show.new(options, gem_name).run
end
desc "list", "List all gems in the bundle"
- method_option "name-only", type: :boolean, banner: "print only the gem names"
- method_option "only-group", type: :array, default: [], banner: "print gems from a given set of groups"
- method_option "without-group", type: :array, default: [], banner: "print all gems except from a given set of groups"
- method_option "paths", type: :boolean, banner: "print the path to each gem in the bundle"
+ method_option "name-only", :type => :boolean, :banner => "print only the gem names"
+ method_option "only-group", :type => :array, :default => [], :banner => "print gems from a given set of groups"
+ method_option "without-group", :type => :array, :default => [], :banner => "print all gems except from a given set of groups"
+ method_option "paths", :type => :boolean, :banner => "print the path to each gem in the bundle"
def list
require_relative "cli/list"
List.new(options).run
@@ -313,8 +339,8 @@ module Bundler
map aliases_for("list")
desc "info GEM [OPTIONS]", "Show information for the given gem"
- method_option "path", type: :boolean, banner: "Print full path to gem"
- method_option "version", type: :boolean, banner: "Print gem version"
+ method_option "path", :type => :boolean, :banner => "Print full path to gem"
+ method_option "version", :type => :boolean, :banner => "Print gem version"
def info(gem_name)
require_relative "cli/info"
Info.new(options, gem_name).run
@@ -326,12 +352,18 @@ module Bundler
or the --binstubs directory if one has been set. Calling binstubs with [GEM [GEM]]
will create binstubs for all given gems.
D
- method_option "force", type: :boolean, default: false, banner: "Overwrite existing binstubs if they exist"
- method_option "path", type: :string, lazy_default: "bin", banner: "Binstub destination directory (default bin)"
- method_option "shebang", type: :string, banner: "Specify a different shebang executable name than the default (usually 'ruby')"
- method_option "standalone", type: :boolean, banner: "Make binstubs that can work without the Bundler runtime"
- method_option "all", type: :boolean, banner: "Install binstubs for all gems"
- method_option "all-platforms", type: :boolean, default: false, banner: "Install binstubs for all platforms"
+ method_option "force", :type => :boolean, :default => false, :banner =>
+ "Overwrite existing binstubs if they exist"
+ method_option "path", :type => :string, :lazy_default => "bin", :banner =>
+ "Binstub destination directory (default bin)"
+ method_option "shebang", :type => :string, :banner =>
+ "Specify a different shebang executable name than the default (usually 'ruby')"
+ method_option "standalone", :type => :boolean, :banner =>
+ "Make binstubs that can work without the Bundler runtime"
+ method_option "all", :type => :boolean, :banner =>
+ "Install binstubs for all gems"
+ method_option "all-platforms", :type => :boolean, :default => false, :banner =>
+ "Install binstubs for all platforms"
def binstubs(*gems)
require_relative "cli/binstubs"
Binstubs.new(options, gems).run
@@ -341,19 +373,19 @@ module Bundler
long_desc <<-D
Adds the specified gem to Gemfile (if valid) and run 'bundle install' in one step.
D
- method_option "version", aliases: "-v", type: :string
- method_option "group", aliases: "-g", type: :string
- method_option "source", aliases: "-s", type: :string
- method_option "require", aliases: "-r", type: :string, banner: "Adds require path to gem. Provide false, or a path as a string."
- method_option "path", type: :string
- method_option "git", type: :string
- method_option "github", type: :string
- method_option "branch", type: :string
- method_option "ref", type: :string
- method_option "glob", type: :string, banner: "The location of a dependency's .gemspec, expanded within Ruby (single quotes recommended)"
- method_option "skip-install", type: :boolean, banner: "Adds gem to the Gemfile but does not install it"
- method_option "optimistic", type: :boolean, banner: "Adds optimistic declaration of version to gem"
- method_option "strict", type: :boolean, banner: "Adds strict declaration of version to gem"
+ method_option "version", :aliases => "-v", :type => :string
+ method_option "group", :aliases => "-g", :type => :string
+ method_option "source", :aliases => "-s", :type => :string
+ method_option "require", :aliases => "-r", :type => :string, :banner => "Adds require path to gem. Provide false, or a path as a string."
+ method_option "path", :type => :string
+ method_option "git", :type => :string
+ method_option "github", :type => :string
+ method_option "branch", :type => :string
+ method_option "ref", :type => :string
+ method_option "skip-install", :type => :boolean, :banner =>
+ "Adds gem to the Gemfile but does not install it"
+ method_option "optimistic", :type => :boolean, :banner => "Adds optimistic declaration of version to gem"
+ method_option "strict", :type => :boolean, :banner => "Adds strict declaration of version to gem"
def add(*gems)
require_relative "cli/add"
Add.new(options.dup, gems).run
@@ -369,45 +401,54 @@ module Bundler
For more information on patch level options (--major, --minor, --patch,
--strict) see documentation on the same options on the update command.
D
- method_option "group", type: :string, banner: "List gems from a specific group"
- method_option "groups", type: :boolean, banner: "List gems organized by groups"
- method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead"
- method_option "pre", type: :boolean, banner: "Check for newer pre-release gems"
- method_option "source", type: :array, banner: "Check against a specific source"
- method_option "filter-strict", type: :boolean, aliases: "--strict", banner: "Only list newer versions allowed by your Gemfile requirements"
- method_option "update-strict", type: :boolean, banner: "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major"
- method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version"
- method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)"
- method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version"
- method_option "filter-major", type: :boolean, banner: "Only list major newer versions"
- method_option "filter-minor", type: :boolean, banner: "Only list minor newer versions"
- method_option "filter-patch", type: :boolean, banner: "Only list patch newer versions"
- method_option "parseable", aliases: "--porcelain", type: :boolean, banner: "Use minimal formatting for more parseable output"
- method_option "only-explicit", type: :boolean, banner: "Only list gems specified in your Gemfile, not their dependencies"
+ method_option "group", :type => :string, :banner => "List gems from a specific group"
+ method_option "groups", :type => :boolean, :banner => "List gems organized by groups"
+ method_option "local", :type => :boolean, :banner =>
+ "Do not attempt to fetch gems remotely and use the gem cache instead"
+ method_option "pre", :type => :boolean, :banner => "Check for newer pre-release gems"
+ method_option "source", :type => :array, :banner => "Check against a specific source"
+ method_option "filter-strict", :type => :boolean, :aliases => "--strict", :banner =>
+ "Only list newer versions allowed by your Gemfile requirements"
+ method_option "update-strict", :type => :boolean, :banner =>
+ "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major"
+ method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version"
+ method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)"
+ method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version"
+ method_option "filter-major", :type => :boolean, :banner => "Only list major newer versions"
+ method_option "filter-minor", :type => :boolean, :banner => "Only list minor newer versions"
+ method_option "filter-patch", :type => :boolean, :banner => "Only list patch newer versions"
+ method_option "parseable", :aliases => "--porcelain", :type => :boolean, :banner =>
+ "Use minimal formatting for more parseable output"
+ method_option "only-explicit", :type => :boolean, :banner =>
+ "Only list gems specified in your Gemfile, not their dependencies"
def outdated(*gems)
require_relative "cli/outdated"
Outdated.new(options, gems).run
end
desc "fund [OPTIONS]", "Lists information about gems seeking funding assistance"
- method_option "group", aliases: "-g", type: :array, banner: "Fetch funding information for a specific group"
+ method_option "group", :aliases => "-g", :type => :array, :banner =>
+ "Fetch funding information for a specific group"
def fund
require_relative "cli/fund"
Fund.new(options).run
end
desc "cache [OPTIONS]", "Locks and then caches all of the gems into vendor/cache"
- method_option "all", type: :boolean,
- default: Bundler.feature_flag.cache_all?,
- banner: "Include all sources (including path and git)."
- method_option "all-platforms", type: :boolean, banner: "Include gems for all platforms present in the lockfile, not only the current one"
- method_option "cache-path", type: :string, banner: "Specify a different cache path than the default (vendor/cache)."
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "no-install", type: :boolean, banner: "Don't install the gems, only update the cache."
- method_option "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache."
- method_option "path", type: :string, banner: "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
- method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
- method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install"
+ method_option "all", :type => :boolean,
+ :default => Bundler.feature_flag.cache_all?,
+ :banner => "Include all sources (including path and git)."
+ method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one"
+ method_option "cache-path", :type => :string, :banner =>
+ "Specify a different cache path than the default (vendor/cache)."
+ method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile"
+ method_option "no-install", :type => :boolean, :banner => "Don't install the gems, only update the cache."
+ method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
+ method_option "path", :type => :string, :banner =>
+ "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
+ method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors."
+ method_option "frozen", :type => :boolean, :banner =>
+ "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install"
long_desc <<-D
The cache command will copy the .gem files for every gem in the bundle into the
directory ./vendor/cache. If you then check that directory into your source
@@ -415,20 +456,17 @@ module Bundler
bundle without having to download any additional gems.
D
def cache
- print_remembered_flag_deprecation("--all", "cache_all", "true") if ARGV.include?("--all")
-
- if ARGV.include?("--path")
- message =
- "The `--path` flag is deprecated because its semantics are unclear. " \
- "Use `bundle config cache_path` to configure the path of your cache of gems, " \
- "and `bundle config path` to configure the path where your gems are installed, " \
- "and stop using this flag"
- removed_message =
- "The `--path` flag has been removed because its semantics were unclear. " \
- "Use `bundle config cache_path` to configure the path of your cache of gems, " \
- "and `bundle config path` to configure the path where your gems are installed."
- SharedHelpers.major_deprecation 2, message, removed_message: removed_message
- end
+ SharedHelpers.major_deprecation 2,
+ "The `--all` flag is deprecated because it relies on being " \
+ "remembered across bundler invocations, which bundler will no longer " \
+ "do in future versions. Instead please use `bundle config set cache_all true`, " \
+ "and stop using this flag" if ARGV.include?("--all")
+
+ SharedHelpers.major_deprecation 2,
+ "The `--path` flag is deprecated because its semantics are unclear. " \
+ "Use `bundle config cache_path` to configure the path of your cache of gems, " \
+ "and `bundle config path` to configure the path where your gems are installed, " \
+ "and stop using this flag" if ARGV.include?("--path")
require_relative "cli/cache"
Cache.new(options).run
@@ -437,8 +475,8 @@ module Bundler
map aliases_for("cache")
desc "exec [OPTIONS]", "Run the command in context of the bundle"
- method_option :keep_file_descriptors, type: :boolean, default: true
- method_option :gemfile, type: :string, required: false
+ method_option :keep_file_descriptors, :type => :boolean, :default => true
+ method_option :gemfile, :type => :string, :required => false
long_desc <<-D
Exec runs a command, providing it access to the gems in the bundle. While using
bundle exec you can require and call the bundled gems as if they were installed
@@ -446,9 +484,7 @@ module Bundler
D
def exec(*args)
if ARGV.include?("--no-keep-file-descriptors")
- message = "The `--no-keep-file-descriptors` has been deprecated. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to"
- removed_message = "The `--no-keep-file-descriptors` has been removed. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to"
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message)
+ SharedHelpers.major_deprecation(2, "The `--no-keep-file-descriptors` has been deprecated. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to")
end
require_relative "cli/exec"
@@ -473,7 +509,7 @@ module Bundler
subcommand "config", Config
desc "open GEM", "Opens the source directory of the given bundled gem"
- method_option "path", type: :string, lazy_default: "", banner: "Open relative path of the gem source."
+ method_option "path", :type => :string, :lazy_default => "", :banner => "Open relative path of the gem source."
def open(name)
require_relative "cli/open"
Open.new(options, name).run
@@ -518,17 +554,17 @@ module Bundler
end
unless Bundler.feature_flag.bundler_3_mode?
- desc "viz [OPTIONS]", "Generates a visual dependency graph", hide: true
+ desc "viz [OPTIONS]", "Generates a visual dependency graph", :hide => true
long_desc <<-D
Viz generates a PNG file of the current Gemfile as a dependency graph.
Viz requires the ruby-graphviz gem (and its dependencies).
The associated gems must also be installed via 'bundle install'.
D
- method_option :file, type: :string, default: "gem_graph", aliases: "-f", desc: "The name to use for the generated file. see format option"
- method_option :format, type: :string, default: "png", aliases: "-F", desc: "This is output format option. Supported format is png, jpg, svg, dot ..."
- method_option :requirements, type: :boolean, default: false, aliases: "-R", desc: "Set to show the version of each required dependency."
- method_option :version, type: :boolean, default: false, aliases: "-v", desc: "Set to show each gem version."
- method_option :without, type: :array, default: [], aliases: "-W", banner: "GROUP[ GROUP...]", desc: "Exclude gems that are part of the specified named group."
+ method_option :file, :type => :string, :default => "gem_graph", :aliases => "-f", :desc => "The name to use for the generated file. see format option"
+ method_option :format, :type => :string, :default => "png", :aliases => "-F", :desc => "This is output format option. Supported format is png, jpg, svg, dot ..."
+ method_option :requirements, :type => :boolean, :default => false, :aliases => "-R", :desc => "Set to show the version of each required dependency."
+ method_option :version, :type => :boolean, :default => false, :aliases => "-v", :desc => "Set to show each gem version."
+ method_option :without, :type => :array, :default => [], :aliases => "-W", :banner => "GROUP[ GROUP...]", :desc => "Exclude gems that are part of the specified named group."
def viz
SharedHelpers.major_deprecation 2, "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph"
require_relative "cli/viz"
@@ -539,26 +575,23 @@ module Bundler
old_gem = instance_method(:gem)
desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem"
- method_option :exe, type: :boolean, default: false, aliases: ["--bin", "-b"], desc: "Generate a binary executable for your library."
- method_option :coc, type: :boolean, desc: "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`."
- method_option :edit, type: :string, aliases: "-e", required: false, banner: "EDITOR",
- lazy_default: [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? },
- desc: "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)"
- method_option :ext, type: :string, desc: "Generate the boilerplate for C extension code.", enum: EXTENSIONS
- method_option :git, type: :boolean, default: true, desc: "Initialize a git repo inside your library."
- method_option :mit, type: :boolean, desc: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`."
- method_option :rubocop, type: :boolean, desc: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`."
- method_option :changelog, type: :boolean, desc: "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`."
- method_option :test, type: :string, lazy_default: Bundler.settings["gem.test"] || "", aliases: "-t", banner: "Use the specified test framework for your library",
- enum: %w[rspec minitest test-unit],
- desc: "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`."
- method_option :ci, type: :string, lazy_default: Bundler.settings["gem.ci"] || "",
- enum: %w[github gitlab circle],
- desc: "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`"
- method_option :linter, type: :string, lazy_default: Bundler.settings["gem.linter"] || "",
- enum: %w[rubocop standard],
- desc: "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`"
- method_option :github_username, type: :string, default: Bundler.settings["gem.github_username"], banner: "Set your username on GitHub", desc: "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username <your_username>`."
+ method_option :exe, :type => :boolean, :default => false, :aliases => ["--bin", "-b"], :desc => "Generate a binary executable for your library."
+ method_option :coc, :type => :boolean, :desc => "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`."
+ method_option :edit, :type => :string, :aliases => "-e", :required => false, :banner => "EDITOR",
+ :lazy_default => [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? },
+ :desc => "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)"
+ method_option :ext, :type => :string, :desc => "Generate the boilerplate for C extension code.", :enum => EXTENSIONS
+ method_option :git, :type => :boolean, :default => true, :desc => "Initialize a git repo inside your library."
+ method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`."
+ method_option :rubocop, :type => :boolean, :desc => "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`."
+ method_option :changelog, :type => :boolean, :desc => "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`."
+ method_option :test, :type => :string, :lazy_default => Bundler.settings["gem.test"] || "", :aliases => "-t", :banner => "Use the specified test framework for your library",
+ :desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`."
+ method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "",
+ :desc => "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`"
+ method_option :linter, :type => :string, :lazy_default => Bundler.settings["gem.linter"] || "",
+ :desc => "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`"
+ method_option :github_username, :type => :string, :default => Bundler.settings["gem.github_username"], :banner => "Set your username on GitHub", :desc => "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username <your_username>`."
def gem(name)
end
@@ -589,24 +622,29 @@ module Bundler
File.expand_path("templates", __dir__)
end
- desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", hide: true
- method_option "dry-run", type: :boolean, default: false, banner: "Only print out changes, do not clean gems"
- method_option "force", type: :boolean, default: false, banner: "Forces cleaning up unused gems even if Bundler is configured to use globally installed gems. As a consequence, removes all system gems except for the ones in the current application."
+ desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", :hide => true
+ method_option "dry-run", :type => :boolean, :default => false, :banner =>
+ "Only print out changes, do not clean gems"
+ method_option "force", :type => :boolean, :default => false, :banner =>
+ "Forces cleaning up unused gems even if Bundler is configured to use globally installed gems. As a consequence, removes all system gems except for the ones in the current application."
def clean
require_relative "cli/clean"
Clean.new(options.dup).run
end
desc "platform [OPTIONS]", "Displays platform compatibility information"
- method_option "ruby", type: :boolean, default: false, banner: "only display ruby related platform information"
+ method_option "ruby", :type => :boolean, :default => false, :banner =>
+ "only display ruby related platform information"
def platform
require_relative "cli/platform"
Platform.new(options).run
end
- desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", hide: true
- method_option "source", type: :string, banner: "Install gem from the given source"
- method_option "group", type: :string, banner: "Install gem into a bundler group"
+ desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", :hide => true
+ method_option "source", :type => :string, :banner =>
+ "Install gem from the given source"
+ method_option "group", :type => :string, :banner =>
+ "Install gem into a bundler group"
def inject(name, version)
SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command"
require_relative "cli/inject"
@@ -614,21 +652,36 @@ module Bundler
end
desc "lock", "Creates a lockfile without installing"
- method_option "update", type: :array, lazy_default: true, banner: "ignore the existing lockfile, update all gems by default, or update list of given gems"
- method_option "local", type: :boolean, default: false, banner: "do not attempt to fetch remote gemspecs and use the local gem cache only"
- method_option "print", type: :boolean, default: false, banner: "print the lockfile to STDOUT instead of writing to the file system"
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "lockfile", type: :string, default: nil, banner: "the path the lockfile should be written to"
- method_option "full-index", type: :boolean, default: false, banner: "Fall back to using the single-file index of all gems"
- method_option "add-platform", type: :array, default: [], banner: "Add a new platform to the lockfile"
- method_option "remove-platform", type: :array, default: [], banner: "Remove a platform from the lockfile"
- method_option "patch", type: :boolean, banner: "If updating, prefer updating only to next patch version"
- method_option "minor", type: :boolean, banner: "If updating, prefer updating only to next minor version"
- method_option "major", type: :boolean, banner: "If updating, prefer updating to next major version (default)"
- method_option "pre", type: :boolean, banner: "If updating, always choose the highest allowed version, regardless of prerelease status"
- method_option "strict", type: :boolean, banner: "If updating, do not allow any gem to be updated past latest --patch | --minor | --major"
- method_option "conservative", type: :boolean, banner: "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated"
- method_option "bundler", type: :string, lazy_default: "> 0.a", banner: "Update the locked version of bundler"
+ method_option "update", :type => :array, :lazy_default => true, :banner =>
+ "ignore the existing lockfile, update all gems by default, or update list of given gems"
+ method_option "local", :type => :boolean, :default => false, :banner =>
+ "do not attempt to fetch remote gemspecs and use the local gem cache only"
+ method_option "print", :type => :boolean, :default => false, :banner =>
+ "print the lockfile to STDOUT instead of writing to the file system"
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "lockfile", :type => :string, :default => nil, :banner =>
+ "the path the lockfile should be written to"
+ method_option "full-index", :type => :boolean, :default => false, :banner =>
+ "Fall back to using the single-file index of all gems"
+ method_option "add-platform", :type => :array, :default => [], :banner =>
+ "Add a new platform to the lockfile"
+ method_option "remove-platform", :type => :array, :default => [], :banner =>
+ "Remove a platform from the lockfile"
+ method_option "patch", :type => :boolean, :banner =>
+ "If updating, prefer updating only to next patch version"
+ method_option "minor", :type => :boolean, :banner =>
+ "If updating, prefer updating only to next minor version"
+ method_option "major", :type => :boolean, :banner =>
+ "If updating, prefer updating to next major version (default)"
+ method_option "pre", :type => :boolean, :banner =>
+ "If updating, always choose the highest allowed version, regardless of prerelease status"
+ method_option "strict", :type => :boolean, :banner =>
+ "If updating, do not allow any gem to be updated past latest --patch | --minor | --major"
+ method_option "conservative", :type => :boolean, :banner =>
+ "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated"
+ method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner =>
+ "Update the locked version of bundler"
def lock
require_relative "cli/lock"
Lock.new(options).run
@@ -645,8 +698,10 @@ module Bundler
missing dependencies are detected, Bundler prints them and exits status 1.
Otherwise, Bundler prints a success message and exits with a status of 0.
D
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "quiet", :type => :boolean, :banner =>
+ "Only output warnings and errors."
def doctor
require_relative "cli/doctor"
Doctor.new(options).run
@@ -666,9 +721,7 @@ module Bundler
D
def pristine(*gems)
require_relative "cli/pristine"
- Bundler.settings.temporary(no_install: false) do
- Pristine.new(gems).run
- end
+ Pristine.new(gems).run
end
if Bundler.feature_flag.plugins?
@@ -689,6 +742,7 @@ module Bundler
exec_used = args.index {|a| exec_commands.include? a }
command = args.find {|a| bundler_commands.include? a }
+ command = all_aliases[command] if all_aliases[command]
if exec_used && help_used
if exec_used + help_used == 1
@@ -709,16 +763,14 @@ module Bundler
# when deprecated version of `--ext` is called
# print out deprecation warning and pretend `--ext=c` was provided
if deprecated_ext_value?(arguments)
- message = "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been deprecated. Please select a language, e.g. `--ext=rust` to generate a Rust extension. This gem will now be generated as if `--ext=c` was used."
- removed_message = "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been removed. Please select a language, e.g. `--ext=rust` to generate a Rust extension."
- SharedHelpers.major_deprecation 2, message, removed_message: removed_message
+ SharedHelpers.major_deprecation 2, "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been deprecated. Please select a language, e.g. `--ext=rust` to generate a Rust extension. This gem will now be generated as if `--ext=c` was used."
arguments[arguments.index("--ext")] = "--ext=c"
end
end
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`
@@ -741,6 +793,26 @@ module Bundler
private
+ # Automatically invoke `bundle install` and resume if
+ # Bundler.settings[:auto_install] exists. This is set through config cmd
+ # `bundle config set --global auto_install 1`.
+ #
+ # Note that this method `nil`s out the global Definition object, so it
+ # should be called first, before you instantiate anything like an
+ # `Installer` that'll keep a reference to the old one instead.
+ def auto_install
+ return unless Bundler.settings[:auto_install]
+
+ begin
+ Bundler.definition.specs
+ rescue GemNotFound
+ Bundler.ui.info "Automatically installing missing gems."
+ Bundler.reset!
+ invoke :install, []
+ Bundler.reset!
+ end
+ end
+
def current_command
_, _, config = @_initializer
config[:current_command]
@@ -770,10 +842,13 @@ module Bundler
return unless SharedHelpers.md5_available?
- require_relative "vendored_uri"
- remote = Source::Rubygems::Remote.new(Gem::URI("https://rubygems.org"))
- cache_path = Bundler.user_cache.join("compact_index", remote.cache_slug)
- latest = Bundler::CompactIndexClient.new(cache_path).latest_version("bundler")
+ latest = Fetcher::CompactIndex.
+ new(nil, Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org")), nil).
+ send(:compact_index_client).
+ instance_variable_get(:@cache).
+ dependencies("bundler").
+ map {|d| Gem::Version.new(d.first) }.
+ max
return unless latest
current = Gem::Version.new(VERSION)
@@ -807,23 +882,12 @@ module Bundler
value = options[name]
value = value.join(" ").to_s if option.type == :array
- value = "'#{value}'" unless option.type == :boolean
- print_remembered_flag_deprecation(flag_name, name.tr("-", "_"), value)
- end
-
- def print_remembered_flag_deprecation(flag_name, option_name, option_value)
- message =
+ Bundler::SharedHelpers.major_deprecation 2,
"The `#{flag_name}` flag is deprecated because it relies on being " \
"remembered across bundler invocations, which bundler will no longer " \
- "do in future versions. Instead please use `bundle config set #{option_name} " \
- "#{option_value}`, and stop using this flag"
- removed_message =
- "The `#{flag_name}` flag has been removed because it relied on being " \
- "remembered across bundler invocations, which bundler will no longer " \
- "do. Instead please use `bundle config set #{option_name} " \
- "#{option_value}`, and stop using this flag"
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
+ "do in future versions. Instead please use `bundle config set --local #{name.tr("-", "_")} " \
+ "'#{value}'`, and stop using this flag"
end
end
end
diff --git a/lib/bundler/cli/add.rb b/lib/bundler/cli/add.rb
index 2b300e1783..08fa6547fb 100644
--- a/lib/bundler/cli/add.rb
+++ b/lib/bundler/cli/add.rb
@@ -28,13 +28,13 @@ module Bundler
dependencies = gems.map {|g| Bundler::Dependency.new(g, version, options) }
Injector.inject(dependencies,
- conservative_versioning: options[:version].nil?, # Perform conservative versioning only when version is not specified
- optimistic: options[:optimistic],
- strict: options[:strict])
+ :conservative_versioning => options[:version].nil?, # Perform conservative versioning only when version is not specified
+ :optimistic => options[:optimistic],
+ :strict => options[:strict])
end
def validate_options!
- raise InvalidOption, "You cannot specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic]
+ raise InvalidOption, "You can not specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic]
# raise error when no gems are specified
raise InvalidOption, "Please specify gems to add." if gems.empty?
diff --git a/lib/bundler/cli/binstubs.rb b/lib/bundler/cli/binstubs.rb
index 8ce138df96..88d071571f 100644
--- a/lib/bundler/cli/binstubs.rb
+++ b/lib/bundler/cli/binstubs.rb
@@ -11,15 +11,15 @@ module Bundler
def run
Bundler.definition.validate_runtime!
path_option = options["path"]
- path_option = nil if path_option&.empty?
+ path_option = nil if path_option && path_option.empty?
Bundler.settings.set_command_option :bin, path_option if options["path"]
Bundler.settings.set_command_option_if_given :shebang, options["shebang"]
installer = Installer.new(Bundler.root, Bundler.definition)
installer_opts = {
- force: options[:force],
- binstubs_cmd: true,
- all_platforms: options["all-platforms"],
+ :force => options[:force],
+ :binstubs_cmd => true,
+ :all_platforms => options["all-platforms"],
}
if options[:all]
@@ -45,7 +45,7 @@ module Bundler
next
end
- Bundler.settings.temporary(path: Bundler.settings[:path] || Bundler.root) do
+ Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do
installer.generate_standalone_bundler_executable_stubs(spec, installer_opts)
end
else
diff --git a/lib/bundler/cli/cache.rb b/lib/bundler/cli/cache.rb
index 2e63a16ec3..c8698ed7e3 100644
--- a/lib/bundler/cli/cache.rb
+++ b/lib/bundler/cli/cache.rb
@@ -19,7 +19,7 @@ module Bundler
# TODO: move cache contents here now that all bundles are locked
custom_path = Bundler.settings[:path] if options[:path]
- Bundler.settings.temporary(cache_all_platforms: options["all-platforms"]) do
+ Bundler.settings.temporary(:cache_all_platforms => options["all-platforms"]) do
Bundler.load.cache(custom_path)
end
end
diff --git a/lib/bundler/cli/check.rb b/lib/bundler/cli/check.rb
index 2adf59d5d5..cc1f37f0c3 100644
--- a/lib/bundler/cli/check.rb
+++ b/lib/bundler/cli/check.rb
@@ -17,7 +17,7 @@ module Bundler
begin
definition.resolve_only_locally!
not_installed = definition.missing_specs
- rescue GemNotFound, GitError, SolveFailure
+ rescue GemNotFound, SolveFailure
Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies."
Bundler.ui.warn "Install missing gems with `bundle install`."
exit 1
@@ -29,10 +29,10 @@ 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"]
+ Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"]
Bundler.ui.info "The Gemfile's dependencies are satisfied"
end
end
diff --git a/lib/bundler/cli/common.rb b/lib/bundler/cli/common.rb
index 7ef6deb2cf..d654406f65 100644
--- a/lib/bundler/cli/common.rb
+++ b/lib/bundler/cli/common.rb
@@ -54,12 +54,9 @@ module Bundler
Bundler.definition.specs.each do |spec|
return spec if spec.name == name
- specs << spec if regexp && spec.name.match?(regexp)
+ specs << spec if regexp && spec.name =~ regexp
end
- default_spec = default_gem_spec(name)
- specs << default_spec if default_spec
-
case specs.count
when 0
dep_in_other_group = Bundler.definition.current_dependencies.find {|dep|dep.name == name }
@@ -78,11 +75,6 @@ module Bundler
raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies)
end
- def self.default_gem_spec(name)
- gem_spec = Gem::Specification.find_all_by_name(name).last
- gem_spec if gem_spec&.default_gem?
- end
-
def self.ask_for_spec_from(specs)
specs.each_with_index do |spec, index|
Bundler.ui.info "#{index.succ} : #{spec.name}", true
diff --git a/lib/bundler/cli/config.rb b/lib/bundler/cli/config.rb
index 77b502fe60..e1222c75dd 100644
--- a/lib/bundler/cli/config.rb
+++ b/lib/bundler/cli/config.rb
@@ -2,17 +2,17 @@
module Bundler
class CLI::Config < Thor
- class_option :parseable, type: :boolean, banner: "Use minimal formatting for more parseable output"
+ class_option :parseable, :type => :boolean, :banner => "Use minimal formatting for more parseable output"
def self.scope_options
- method_option :global, type: :boolean, banner: "Only change the global config"
- method_option :local, type: :boolean, banner: "Only change the local config"
+ method_option :global, :type => :boolean, :banner => "Only change the global config"
+ method_option :local, :type => :boolean, :banner => "Only change the local config"
end
private_class_method :scope_options
- desc "base NAME [VALUE]", "The Bundler 1 config interface", hide: true
+ desc "base NAME [VALUE]", "The Bundler 1 config interface", :hide => true
scope_options
- method_option :delete, type: :boolean, banner: "delete"
+ method_option :delete, :type => :boolean, :banner => "delete"
def base(name = nil, *value)
new_args =
if ARGV.size == 1
@@ -25,9 +25,8 @@ module Bundler
["config", "get", ARGV[1]]
end
- message = "Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle #{new_args.join(" ")}` instead."
- removed_message = "Using the `config` command without a subcommand [list, get, set, unset] is has been removed. Use `bundle #{new_args.join(" ")}` instead."
- SharedHelpers.major_deprecation 3, message, removed_message: removed_message
+ SharedHelpers.major_deprecation 3,
+ "Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle #{new_args.join(" ")}` instead."
Base.new(options, name, value, self).run
end
diff --git a/lib/bundler/cli/console.rb b/lib/bundler/cli/console.rb
index 840cf14fd7..1eb8ea8254 100644
--- a/lib/bundler/cli/console.rb
+++ b/lib/bundler/cli/console.rb
@@ -9,9 +9,8 @@ module Bundler
end
def run
- message = "bundle console will be replaced by `bin/console` generated by `bundle gem <name>`"
- removed_message = "bundle console has been replaced by `bin/console` generated by `bundle gem <name>`"
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
+ Bundler::SharedHelpers.major_deprecation 2, "bundle console will be replaced " \
+ "by `bin/console` generated by `bundle gem <name>`"
group ? Bundler.require(:default, *group.split(" ").map!(&:to_sym)) : Bundler.require
ARGV.clear
diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb
index 1f6fc93c16..e299a5a8c2 100644
--- a/lib/bundler/cli/doctor.rb
+++ b/lib/bundler/cli/doctor.rb
@@ -6,8 +6,8 @@ require "fiddle"
module Bundler
class CLI::Doctor
- DARWIN_REGEX = /\s+(.+) \(compatibility /
- LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/
+ DARWIN_REGEX = /\s+(.+) \(compatibility /.freeze
+ LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/.freeze
attr_reader :options
diff --git a/lib/bundler/cli/exec.rb b/lib/bundler/cli/exec.rb
index f81cd5d2c4..42b602a055 100644
--- a/lib/bundler/cli/exec.rb
+++ b/lib/bundler/cli/exec.rb
@@ -12,7 +12,7 @@ module Bundler
@options = options
@cmd = args.shift
@args = args
- @args << { close_others: !options.keep_file_descriptors? } unless Bundler.current_ruby.jruby?
+ @args << { :close_others => !options.keep_file_descriptors? } unless Bundler.current_ruby.jruby?
end
def run
diff --git a/lib/bundler/cli/fund.rb b/lib/bundler/cli/fund.rb
index ad7f31f3d6..52db5aef68 100644
--- a/lib/bundler/cli/fund.rb
+++ b/lib/bundler/cli/fund.rb
@@ -16,7 +16,7 @@ module Bundler
deps = if groups.any?
Bundler.definition.dependencies_for(groups)
else
- Bundler.definition.requested_dependencies
+ Bundler.definition.current_dependencies
end
fund_info = deps.each_with_object([]) do |dep, arr|
diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb
index fb0a184e5d..7f1200f4a0 100644
--- a/lib/bundler/cli/gem.rb
+++ b/lib/bundler/cli/gem.rb
@@ -11,7 +11,7 @@ module Bundler
class CLI::Gem
TEST_FRAMEWORK_VERSIONS = {
"rspec" => "3.0",
- "minitest" => "5.16",
+ "minitest" => "5.0",
"test-unit" => "3.0",
}.freeze
@@ -32,6 +32,7 @@ module Bundler
validate_ext_name if @extension
validate_rust_builder_rubygems_version if @extension == "rust"
+ travis_removal_info
end
def run
@@ -58,28 +59,28 @@ module Bundler
end
config = {
- name: name,
- underscored_name: underscored_name,
- namespaced_path: namespaced_path,
- makefile_path: "#{underscored_name}/#{underscored_name}",
- constant_name: constant_name,
- constant_array: constant_array,
- author: git_author_name.empty? ? "TODO: Write your name" : git_author_name,
- email: git_user_email.empty? ? "TODO: Write your email address" : git_user_email,
- test: options[:test],
- ext: extension,
- exe: options[:exe],
- bundler_version: bundler_dependency_version,
- git: use_git,
- github_username: github_username.empty? ? "[USERNAME]" : github_username,
- required_ruby_version: required_ruby_version,
- rust_builder_required_rubygems_version: rust_builder_required_rubygems_version,
- minitest_constant_name: minitest_constant_name,
+ :name => name,
+ :underscored_name => underscored_name,
+ :namespaced_path => namespaced_path,
+ :makefile_path => "#{underscored_name}/#{underscored_name}",
+ :constant_name => constant_name,
+ :constant_array => constant_array,
+ :author => git_author_name.empty? ? "TODO: Write your name" : git_author_name,
+ :email => git_user_email.empty? ? "TODO: Write your email address" : git_user_email,
+ :test => options[:test],
+ :ext => extension,
+ :exe => options[:exe],
+ :bundler_version => bundler_dependency_version,
+ :git => use_git,
+ :github_username => github_username.empty? ? "[USERNAME]" : github_username,
+ :required_ruby_version => required_ruby_version,
+ :rust_builder_required_rubygems_version => rust_builder_required_rubygems_version,
+ :minitest_constant_name => minitest_constant_name,
}
ensure_safe_gem_name(name, constant_array)
templates = {
- "Gemfile.tt" => Bundler.preferred_gemfile_name,
+ "#{Bundler.preferred_gemfile_name}.tt" => Bundler.preferred_gemfile_name,
"lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb",
"lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb",
"sig/newgem.rbs.tt" => "sig/#{namespaced_path}.rbs",
@@ -136,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?",
@@ -191,10 +189,7 @@ module Bundler
templates.merge!("standard.yml.tt" => ".standard.yml")
end
- if config[:exe]
- templates.merge!("exe/newgem.tt" => "exe/#{name}")
- executables.push("exe/#{name}")
- end
+ templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe]
if extension == "c"
templates.merge!(
@@ -238,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
@@ -278,7 +275,6 @@ module Bundler
end
def ask_and_set_test_framework
- return if skip?(:test)
test_framework = options[:test] || Bundler.settings["gem.test"]
if test_framework.to_s.empty?
@@ -304,10 +300,6 @@ module Bundler
test_framework
end
- def skip?(option)
- options.key?(option) && options[option].nil?
- end
-
def hint_text(setting)
if Bundler.settings["gem.#{setting}"] == false
"Your choice will only be applied to this gem."
@@ -318,7 +310,6 @@ module Bundler
end
def ask_and_set_ci
- return if skip?(:ci)
ci_template = options[:ci] || Bundler.settings["gem.ci"]
if ci_template.to_s.empty?
@@ -350,7 +341,6 @@ module Bundler
end
def ask_and_set_linter
- return if skip?(:linter)
linter_template = options[:linter] || Bundler.settings["gem.linter"]
linter_template = deprecated_rubocop_option if linter_template.nil?
@@ -358,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")
@@ -389,20 +379,15 @@ module Bundler
def deprecated_rubocop_option
if !options[:rubocop].nil?
if options[:rubocop]
- Bundler::SharedHelpers.major_deprecation 2,
- "--rubocop is deprecated, use --linter=rubocop",
- removed_message: "--rubocop has been removed, use --linter=rubocop"
+ Bundler::SharedHelpers.major_deprecation 2, "--rubocop is deprecated, use --linter=rubocop"
"rubocop"
else
- Bundler::SharedHelpers.major_deprecation 2,
- "--no-rubocop is deprecated, use --linter",
- removed_message: "--no-rubocop has been removed, use --linter"
+ Bundler::SharedHelpers.major_deprecation 2, "--no-rubocop is deprecated, use --linter"
false
end
elsif !Bundler.settings["gem.rubocop"].nil?
Bundler::SharedHelpers.major_deprecation 2,
- "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead",
- removed_message: "config gem.rubocop has been removed; we've updated your config to use gem.linter instead"
+ "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
Bundler.settings["gem.rubocop"] ? "rubocop" : false
end
end
@@ -446,7 +431,7 @@ module Bundler
end
def required_ruby_version
- "3.0.0"
+ "2.6.0"
end
def rubocop_version
@@ -457,6 +442,19 @@ module Bundler
"1.3"
end
+ # TODO: remove at next minor release
+ def travis_removal_info
+ if options[:ci] == "travis"
+ Bundler.ui.error "Support for Travis CI was removed from gem skeleton generator."
+ exit 1
+ end
+
+ if Bundler.settings["gem.ci"] == "travis"
+ Bundler.ui.error "Support for Travis CI was removed from gem skeleton generator, but it is present in bundle config. Please configure another provider using `bundle config set gem.ci SERVICE` (where SERVICE is one of github/gitlab/circle) or unset configuration using `bundle config unset gem.ci`."
+ exit 1
+ end
+ end
+
def validate_rust_builder_rubygems_version
if Gem::Version.new(rust_builder_required_rubygems_version) > Gem.rubygems_version
Bundler.ui.error "Your RubyGems version (#{Gem.rubygems_version}) is too old to build Rust extension. Please update your RubyGems using `gem update --system` or any other way and try again."
diff --git a/lib/bundler/cli/info.rb b/lib/bundler/cli/info.rb
index 8f34956aca..0545ce8c75 100644
--- a/lib/bundler/cli/info.rb
+++ b/lib/bundler/cli/info.rb
@@ -25,8 +25,19 @@ module Bundler
private
- def spec_for_gem(name)
- Bundler::CLI::Common.select_spec(name, :regex_match)
+ def spec_for_gem(gem_name)
+ spec = Bundler.definition.specs.find {|s| s.name == gem_name }
+ spec || default_gem_spec(gem_name) || Bundler::CLI::Common.select_spec(gem_name, :regex_match)
+ end
+
+ 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
+ return gem_spec if gem_spec && gem_spec.respond_to?(:default_gem?) && gem_spec.default_gem?
+ end
+
+ def spec_not_found(gem_name)
+ raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(gem_name, Bundler.definition.dependencies)
end
def print_gem_version(spec)
diff --git a/lib/bundler/cli/init.rb b/lib/bundler/cli/init.rb
index 246b9d6460..bc96507c29 100644
--- a/lib/bundler/cli/init.rb
+++ b/lib/bundler/cli/init.rb
@@ -32,7 +32,7 @@ module Bundler
file << spec.to_gemfile
end
else
- File.open(File.expand_path("../templates/Gemfile", __dir__), "r") do |template|
+ File.open(File.expand_path("../templates/#{gemfile}", __dir__), "r") do |template|
File.open(gemfile, "wb") do |destination|
IO.copy_stream(template, destination)
end
@@ -45,7 +45,7 @@ module Bundler
private
def gemfile
- @gemfile ||= options[:gemfile] || Bundler.preferred_gemfile_name
+ @gemfile ||= Bundler.preferred_gemfile_name
end
end
end
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb
index eb6c45e112..1765621cb3 100644
--- a/lib/bundler/cli/install.rb
+++ b/lib/bundler/cli/install.rb
@@ -12,13 +12,9 @@ module Bundler
warn_if_root
- if options[:local]
- Bundler.self_manager.restart_with_locked_bundler_if_needed
- else
- Bundler.self_manager.install_locked_bundler_and_restart_with_it_if_needed
- end
+ Bundler.self_manager.install_locked_bundler_and_restart_with_it_if_needed
- Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Gem.freebsd_platform?
+ Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD
# Disable color in deployment mode
Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment]
@@ -29,12 +25,11 @@ module Bundler
if options[:deployment] || options[:frozen] || Bundler.frozen_bundle?
unless Bundler.default_lockfile.exist?
- flag = "--deployment flag" if options[:deployment]
- flag ||= "--frozen flag" if options[:frozen]
- flag ||= "deployment setting" if Bundler.settings[:deployment]
- flag ||= "frozen setting" if Bundler.settings[:frozen]
- raise ProductionError, "The #{flag} requires a lockfile. Please make " \
- "sure you have checked your #{SharedHelpers.relative_lockfile_path} into version control " \
+ flag = "--deployment flag" if options[:deployment]
+ flag ||= "--frozen flag" if options[:frozen]
+ flag ||= "deployment setting"
+ 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
@@ -56,8 +51,7 @@ module Bundler
if options["binstubs"]
Bundler::SharedHelpers.major_deprecation 2,
- "The --binstubs option will be removed in favor of `bundle binstubs --all`",
- removed_message: "The --binstubs option have been removed in favor of `bundle binstubs --all`"
+ "The --binstubs option will be removed in favor of `bundle binstubs --all`"
end
Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
@@ -67,7 +61,7 @@ module Bundler
installer = Installer.install(Bundler.root, definition, options)
- Bundler.settings.temporary(cache_all_platforms: options[:local] ? false : Bundler.settings[:cache_all_platforms]) do
+ Bundler.settings.temporary(:cache_all_platforms => options[:local] ? false : Bundler.settings[:cache_all_platforms]) do
Bundler.load.cache(nil, options[:local]) if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle?
end
@@ -101,7 +95,7 @@ module Bundler
def warn_if_root
return if Bundler.settings[:silence_root_warning] || Gem.win_platform? || !Process.uid.zero?
Bundler.ui.warn "Don't run Bundler as root. Installing your bundle as root " \
- "will break this application for all non-root users on this machine.", wrap: true
+ "will break this application for all non-root users on this machine.", :wrap => true
end
def dependencies_count_for(definition)
@@ -154,13 +148,13 @@ module Bundler
Bundler.settings.set_command_option_if_given :path, options[:path]
if options["standalone"] && Bundler.settings[:path].nil? && !options["local"]
- Bundler.settings.temporary(path_relative_to_cwd: false) do
+ Bundler.settings.temporary(:path_relative_to_cwd => false) do
Bundler.settings.set_command_option :path, "bundle"
end
end
bin_option = options["binstubs"]
- bin_option = nil if bin_option&.empty?
+ bin_option = nil if bin_option && bin_option.empty?
Bundler.settings.set_command_option :bin, bin_option if options["binstubs"]
Bundler.settings.set_command_option_if_given :shebang, options["shebang"]
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 3f204bdc45..cb3ed27138 100644
--- a/lib/bundler/cli/lock.rb
+++ b/lib/bundler/cli/lock.rb
@@ -15,8 +15,8 @@ module Bundler
end
print = options[:print]
- previous_output_stream = Bundler.ui.output_stream
- Bundler.ui.output_stream = :stderr if print
+ previous_ui_level = Bundler.ui.level
+ Bundler.ui.level = "silent" if print
Bundler::Fetcher.disable_endpoint = options["full-index"]
@@ -26,49 +26,45 @@ module Bundler
if update.is_a?(Array) # unlocking specific gems
Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update)
- update = { gems: update, conservative: conservative }
+ update = { :gems => update, :conservative => conservative }
elsif update && conservative
- update = { conservative: conservative }
+ update = { :conservative => conservative }
elsif update && bundler
- update = { bundler: bundler }
+ update = { :bundler => bundler }
end
+ definition = Bundler.definition(update)
- file = options[:lockfile]
- file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile
+ Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update]
- Bundler.settings.temporary(frozen: false) do
- definition = Bundler.definition(update, file)
-
- 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.error "The platform `#{platform_string}` is unknown to RubyGems and can't be added to the lockfile."
- exit 1
- 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
- puts "Writing lockfile to #{file}"
- definition.lock
- 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.output_stream = previous_output_stream
+ Bundler.ui.level = previous_ui_level
end
end
end
diff --git a/lib/bundler/cli/open.rb b/lib/bundler/cli/open.rb
index f24693b843..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/outdated.rb b/lib/bundler/cli/outdated.rb
index 75fcdca641..12c3384938 100644
--- a/lib/bundler/cli/outdated.rb
+++ b/lib/bundler/cli/outdated.rb
@@ -41,12 +41,12 @@ module Bundler
# We're doing a full update
Bundler.definition(true)
else
- Bundler.definition(gems: gems, sources: sources)
+ Bundler.definition(:gems => gems, :sources => sources)
end
Bundler::CLI::Common.configure_gem_version_promoter(
Bundler.definition,
- options.merge(strict: @strict)
+ options.merge(:strict => @strict)
)
definition_resolution = proc do
@@ -54,7 +54,7 @@ module Bundler
end
if options[:parseable]
- Bundler.ui.progress(&definition_resolution)
+ Bundler.ui.silence(&definition_resolution)
else
definition_resolution.call
end
@@ -90,33 +90,35 @@ module Bundler
end
outdated_gems << {
- active_spec: active_spec,
- current_spec: current_spec,
- dependency: dependency,
- groups: groups,
+ :active_spec => active_spec,
+ :current_spec => current_spec,
+ :dependency => dependency,
+ :groups => groups,
}
end
- relevant_outdated_gems = if options_include_groups
- outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems|
- contains_group = groups.split(", ").include?(options[:group])
- next unless options[:groups] || contains_group
-
- gems
- end.compact
- else
- outdated_gems
- end
-
- if relevant_outdated_gems.empty?
+ if outdated_gems.empty?
unless options[:parseable]
Bundler.ui.info(nothing_outdated_message)
end
else
- if options[:parseable]
- print_gems(relevant_outdated_gems)
+ if options_include_groups
+ relevant_outdated_gems = outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems|
+ contains_group = groups.split(", ").include?(options[:group])
+ next unless options[:groups] || contains_group
+
+ gems
+ end.compact
+
+ if options[:parseable]
+ print_gems(relevant_outdated_gems)
+ else
+ print_gems_table(relevant_outdated_gems)
+ end
+ elsif options[:parseable]
+ print_gems(outdated_gems)
else
- print_gems_table(relevant_outdated_gems)
+ print_gems_table(outdated_gems)
end
exit 1
@@ -192,7 +194,7 @@ module Bundler
end
current_version = "#{current_spec.version}#{current_spec.git_version}"
- if dependency&.specific?
+ if dependency && dependency.specific?
dependency_version = %(, requested #{dependency.requirement})
end
diff --git a/lib/bundler/cli/platform.rb b/lib/bundler/cli/platform.rb
index 32d68abbb1..73da8cf80e 100644
--- a/lib/bundler/cli/platform.rb
+++ b/lib/bundler/cli/platform.rb
@@ -8,12 +8,12 @@ module Bundler
end
def run
- ruby_version = if Bundler.locked_gems
- Bundler.locked_gems.ruby_version&.gsub(/p\d+\Z/, "")
- else
- Bundler.definition.ruby_version&.single_version_string
+ platforms, ruby_version = Bundler.ui.silence do
+ locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version&.gsub(/p\d+\Z/, "")
+ gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string
+ [Bundler.definition.platforms.map {|p| "* #{p}" },
+ locked_ruby_version || gemfile_ruby_version]
end
-
output = []
if options[:ruby]
@@ -23,8 +23,6 @@ module Bundler
output << "No ruby version specified"
end
else
- platforms = Bundler.definition.platforms.map {|p| "* #{p}" }
-
output << "Your platform is: #{Gem::Platform.local}"
output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}"
diff --git a/lib/bundler/cli/plugin.rb b/lib/bundler/cli/plugin.rb
index fd61ef0d95..fe3f4412fa 100644
--- a/lib/bundler/cli/plugin.rb
+++ b/lib/bundler/cli/plugin.rb
@@ -5,15 +5,20 @@ module Bundler
class CLI::Plugin < Thor
desc "install PLUGINS", "Install the plugin from the source"
long_desc <<-D
- Install plugins either from the rubygems source provided (with --source option), from a git source provided with --git, or a local path provided with --path. If no sources are provided, it uses Gem.sources
+ Install plugins either from the rubygems source provided (with --source option) or from a git source provided with --git (for remote repos) or --local_git (for local repos). If no sources are provided, it uses Gem.sources
D
- method_option "source", type: :string, default: nil, banner: "URL of the RubyGems source to fetch the plugin from"
- method_option "version", type: :string, default: nil, banner: "The version of the plugin to fetch"
- method_option "git", type: :string, default: nil, banner: "URL of the git repo to fetch from"
- method_option "local_git", type: :string, default: nil, banner: "Path of the local git repo to fetch from (deprecated)"
- method_option "branch", type: :string, default: nil, banner: "The git branch to checkout"
- method_option "ref", type: :string, default: nil, banner: "The git revision to check out"
- method_option "path", type: :string, default: nil, banner: "Path of a local gem to directly use"
+ method_option "source", :type => :string, :default => nil, :banner =>
+ "URL of the RubyGems source to fetch the plugin from"
+ method_option "version", :type => :string, :default => nil, :banner =>
+ "The version of the plugin to fetch"
+ method_option "git", :type => :string, :default => nil, :banner =>
+ "URL of the git repo to fetch from"
+ method_option "local_git", :type => :string, :default => nil, :banner =>
+ "Path of the local git repo to fetch from"
+ method_option "branch", :type => :string, :default => nil, :banner =>
+ "The git branch to checkout"
+ method_option "ref", :type => :string, :default => nil, :banner =>
+ "The git revision to check out"
def install(*plugins)
Bundler::Plugin.install(plugins, options)
end
@@ -22,7 +27,8 @@ module Bundler
long_desc <<-D
Uninstall given list of plugins. To uninstall all the plugins, use -all option.
D
- method_option "all", type: :boolean, default: nil, banner: "Uninstall all the installed plugins. If no plugin is installed, then it does nothing."
+ method_option "all", :type => :boolean, :default => nil, :banner =>
+ "Uninstall all the installed plugins. If no plugin is installed, then it does nothing."
def uninstall(*plugins)
Bundler::Plugin.uninstall(plugins, options)
end
diff --git a/lib/bundler/cli/pristine.rb b/lib/bundler/cli/pristine.rb
index e0d7452c44..d6654f8053 100644
--- a/lib/bundler/cli/pristine.rb
+++ b/lib/bundler/cli/pristine.rb
@@ -12,48 +12,40 @@ module Bundler
definition.validate_runtime!
installer = Bundler::Installer.new(Bundler.root, definition)
- ProcessLock.lock do
- installed_specs = definition.specs.reject do |spec|
- next if spec.name == "bundler" # Source::Rubygems doesn't install bundler
- next if !@gems.empty? && !@gems.include?(spec.name)
-
- gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})"
- gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY
-
- case source = spec.source
- when Source::Rubygems
- cached_gem = spec.cache_file
- unless File.exist?(cached_gem)
- Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.")
- next
- end
-
- FileUtils.rm_rf spec.full_gem_path
- when Source::Git
- if source.local?
- Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is locally overridden.")
- next
- end
-
- source.remote!
- if extension_cache_path = source.extension_cache_path(spec)
- FileUtils.rm_rf extension_cache_path
- end
- FileUtils.rm_rf spec.extension_dir
- FileUtils.rm_rf spec.full_gem_path
- else
- Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.")
+ Bundler.load.specs.each do |spec|
+ next if spec.name == "bundler" # Source::Rubygems doesn't install bundler
+ next if !@gems.empty? && !@gems.include?(spec.name)
+
+ gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})"
+ gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY
+
+ case source = spec.source
+ when Source::Rubygems
+ cached_gem = spec.cache_file
+ unless File.exist?(cached_gem)
+ Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.")
next
end
- true
- end.map(&:name)
+ FileUtils.rm_rf spec.full_gem_path
+ when Source::Git
+ if source.local?
+ Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is locally overridden.")
+ next
+ end
- jobs = installer.send(:installation_parallelization, {})
- pristine_count = definition.specs.count - installed_specs.count
- # allow a pristining a single gem to skip the parallel worker
- jobs = [jobs, pristine_count].min
- ParallelInstaller.call(installer, definition.specs, jobs, false, true, skip: installed_specs)
+ source.remote!
+ if extension_cache_path = source.extension_cache_path(spec)
+ FileUtils.rm_rf extension_cache_path
+ end
+ FileUtils.rm_rf spec.extension_dir
+ FileUtils.rm_rf spec.full_gem_path
+ else
+ Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.")
+ next
+ end
+
+ Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec
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 985e8db051..b49182655b 100644
--- a/lib/bundler/cli/update.rb
+++ b/lib/bundler/cli/update.rb
@@ -35,7 +35,7 @@ module Bundler
if full_update
if conservative
- Bundler.definition(conservative: conservative)
+ Bundler.definition(:conservative => conservative)
else
Bundler.definition(true)
end
@@ -51,9 +51,9 @@ module Bundler
gems.concat(deps.map(&:name))
end
- Bundler.definition(gems: gems, sources: sources, ruby: options[:ruby],
- conservative: conservative,
- bundler: update_bundler)
+ Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby],
+ :conservative => conservative,
+ :bundler => update_bundler)
end
Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options)
@@ -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"]
@@ -71,7 +70,7 @@ module Bundler
if locked_gems = Bundler.definition.locked_gems
previous_locked_info = locked_gems.specs.reduce({}) do |h, s|
- h[s.name] = { spec: s, version: s.version, source: s.source.identifier }
+ h[s.name] = { :spec => s, :version => s.version, :source => s.source.identifier }
h
end
end
diff --git a/lib/bundler/compact_index_client.rb b/lib/bundler/compact_index_client.rb
index a4f5bb1638..127a50e810 100644
--- a/lib/bundler/compact_index_client.rb
+++ b/lib/bundler/compact_index_client.rb
@@ -4,44 +4,8 @@ require "pathname"
require "set"
module Bundler
- # The CompactIndexClient is responsible for fetching and parsing the compact index.
- #
- # The compact index is a set of caching optimized files that are used to fetch gem information.
- # The files are:
- # - names: a list of all gem names
- # - versions: a list of all gem versions
- # - info/[gem]: a list of all versions of a gem
- #
- # The client is instantiated with:
- # - `directory`: the root directory where the cache files are stored.
- # - `fetcher`: (optional) an object that responds to #call(uri_path, headers) and returns an http response.
- # If the `fetcher` is not provided, the client will only read cached files from disk.
- #
- # The client is organized into:
- # - `Updater`: updates the cached files on disk using the fetcher.
- # - `Cache`: calls the updater, caches files, read and return them from disk
- # - `Parser`: parses the compact index file data
- # - `CacheFile`: a concurrency safe file reader/writer that verifies checksums
- #
- # The client is intended to optimize memory usage and performance.
- # It is called 100s or 1000s of times, parsing files with hundreds of thousands of lines.
- # It may be called concurrently without global interpreter lock in some Rubies.
- # As a result, some methods may look more complex than necessary to save memory or time.
class CompactIndexClient
- # NOTE: MD5 is here not because we expect a server to respond with it, but
- # because we use it to generate the etag on first request during the upgrade
- # to the compact index client that uses opaque etags saved to files.
- # Remove once 2.5.0 has been out for a while.
- SUPPORTED_DIGESTS = { "sha-256" => :SHA256, "md5" => :MD5 }.freeze
DEBUG_MUTEX = Thread::Mutex.new
-
- # info returns an Array of INFO Arrays. Each INFO Array has the following indices:
- INFO_NAME = 0
- INFO_VERSION = 1
- INFO_PLATFORM = 2
- INFO_DEPS = 3
- INFO_REQS = 4
-
def self.debug
return unless ENV["DEBUG_COMPACT_INDEX"]
DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") }
@@ -50,48 +14,106 @@ module Bundler
class Error < StandardError; end
require_relative "compact_index_client/cache"
- require_relative "compact_index_client/cache_file"
- require_relative "compact_index_client/parser"
require_relative "compact_index_client/updater"
- def initialize(directory, fetcher = nil)
- @cache = Cache.new(directory, fetcher)
- @parser = Parser.new(@cache)
+ attr_reader :directory
+
+ def initialize(directory, fetcher)
+ @directory = Pathname.new(directory)
+ @updater = Updater.new(fetcher)
+ @cache = Cache.new(@directory)
+ @endpoints = Set.new
+ @info_checksums_by_name = {}
+ @parsed_checksums = false
+ @mutex = Thread::Mutex.new
+ end
+
+ def execution_mode=(block)
+ Bundler::CompactIndexClient.debug { "execution_mode=" }
+ @endpoints = Set.new
+
+ @execution_mode = block
+ end
+
+ # @return [Lambda] A lambda that takes an array of inputs and a block, and
+ # maps the inputs with the block in parallel.
+ #
+ def execution_mode
+ @execution_mode || sequentially
+ end
+
+ def sequential_execution_mode!
+ self.execution_mode = sequentially
+ end
+
+ def sequentially
+ @sequentially ||= lambda do |inputs, &blk|
+ inputs.map(&blk)
+ end
end
def names
- Bundler::CompactIndexClient.debug { "names" }
- @parser.names
+ Bundler::CompactIndexClient.debug { "/names" }
+ update(@cache.names_path, "names")
+ @cache.names
end
def versions
- Bundler::CompactIndexClient.debug { "versions" }
- @parser.versions
+ Bundler::CompactIndexClient.debug { "/versions" }
+ update(@cache.versions_path, "versions")
+ versions, @info_checksums_by_name = @cache.versions
+ versions
end
def dependencies(names)
Bundler::CompactIndexClient.debug { "dependencies(#{names})" }
- names.map {|name| info(name) }
+ execution_mode.call(names) do |name|
+ update_info(name)
+ @cache.dependencies(name).map {|d| d.unshift(name) }
+ end.flatten(1)
end
- def info(name)
- Bundler::CompactIndexClient.debug { "info(#{name})" }
- @parser.info(name)
+ def update_and_parse_checksums!
+ Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" }
+ return @info_checksums_by_name if @parsed_checksums
+ update(@cache.versions_path, "versions")
+ @info_checksums_by_name = @cache.checksums
+ @parsed_checksums = true
+ end
+
+ private
+
+ def update(local_path, remote_path)
+ Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" }
+ unless synchronize { @endpoints.add?(remote_path) }
+ Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
+ return
+ end
+ @updater.update(local_path, url(remote_path))
end
- def latest_version(name)
- Bundler::CompactIndexClient.debug { "latest_version(#{name})" }
- @parser.info(name).map {|d| Gem::Version.new(d[INFO_VERSION]) }.max
+ def update_info(name)
+ Bundler::CompactIndexClient.debug { "update_info(#{name})" }
+ path = @cache.info_path(name)
+ checksum = @updater.checksum_for_file(path)
+ unless existing = @info_checksums_by_name[name]
+ Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" }
+ return
+ end
+ if checksum == existing
+ Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" }
+ return
+ end
+ Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" }
+ update(path, "info/#{name}")
end
- def available?
- Bundler::CompactIndexClient.debug { "available?" }
- @parser.available?
+ def url(path)
+ path
end
- def reset!
- Bundler::CompactIndexClient.debug { "reset!" }
- @cache.reset!
+ def synchronize
+ @mutex.synchronize { yield }
end
end
end
diff --git a/lib/bundler/compact_index_client/cache.rb b/lib/bundler/compact_index_client/cache.rb
index bedd7f8028..0b43581c11 100644
--- a/lib/bundler/compact_index_client/cache.rb
+++ b/lib/bundler/compact_index_client/cache.rb
@@ -7,89 +7,94 @@ module Bundler
class Cache
attr_reader :directory
- def initialize(directory, fetcher = nil)
+ def initialize(directory)
@directory = Pathname.new(directory).expand_path
- @updater = Updater.new(fetcher) if fetcher
- @mutex = Thread::Mutex.new
- @endpoints = Set.new
-
- @info_root = mkdir("info")
- @special_characters_info_root = mkdir("info-special-characters")
- @info_etag_root = mkdir("info-etags")
+ info_roots.each do |dir|
+ SharedHelpers.filesystem_access(dir) do
+ FileUtils.mkdir_p(dir)
+ end
+ end
end
def names
- fetch("names", names_path, names_etag_path)
+ lines(names_path)
end
- def versions
- fetch("versions", versions_path, versions_etag_path)
+ def names_path
+ directory.join("names")
end
- def info(name, remote_checksum = nil)
- path = info_path(name)
-
- if remote_checksum && remote_checksum != SharedHelpers.checksum_for_file(path, :MD5)
- fetch("info/#{name}", path, info_etag_path(name))
- else
- Bundler::CompactIndexClient.debug { "update skipped info/#{name} (#{remote_checksum ? "versions index checksum is nil" : "versions index checksum matches local"})" }
- read(path)
+ def versions
+ versions_by_name = Hash.new {|hash, key| hash[key] = [] }
+ info_checksums_by_name = {}
+
+ lines(versions_path).each do |line|
+ name, versions_string, info_checksum = line.split(" ", 3)
+ info_checksums_by_name[name] = info_checksum || ""
+ versions_string.split(",").each do |version|
+ 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
end
- end
- def reset!
- @mutex.synchronize { @endpoints.clear }
+ [versions_by_name, info_checksums_by_name]
end
- private
+ def versions_path
+ directory.join("versions")
+ end
- def names_path = directory.join("names")
- def names_etag_path = directory.join("names.etag")
- def versions_path = directory.join("versions")
- def versions_etag_path = directory.join("versions.etag")
+ def checksums
+ checksums = {}
- def info_path(name)
- name = name.to_s
- # TODO: converge this into the info_root by hashing all filenames like info_etag_path
- if /[^a-z0-9_-]/.match?(name)
- name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}"
- @special_characters_info_root.join(name)
- else
- @info_root.join(name)
+ lines(versions_path).each do |line|
+ name, _, checksum = line.split(" ", 3)
+ checksums[name] = checksum
end
- end
- def info_etag_path(name)
- name = name.to_s
- @info_etag_root.join("#{name}-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}")
+ checksums
end
- def mkdir(name)
- directory.join(name).tap do |dir|
- SharedHelpers.filesystem_access(dir) do
- FileUtils.mkdir_p(dir)
- end
+ def dependencies(name)
+ lines(info_path(name)).map do |line|
+ parse_gem(line)
end
end
- def fetch(remote_path, path, etag_path)
- if already_fetched?(remote_path)
- Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
+ def info_path(name)
+ name = name.to_s
+ if /[^a-z0-9_-]/.match?(name)
+ name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}"
+ info_roots.last.join(name)
else
- Bundler::CompactIndexClient.debug { "fetching #{remote_path}" }
- @updater&.update(remote_path, path, etag_path)
+ info_roots.first.join(name)
end
+ end
+
+ private
- read(path)
+ def lines(path)
+ return [] unless path.file?
+ lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n")
+ header = lines.index("---")
+ header ? lines[header + 1..-1] : lines
end
- def already_fetched?(remote_path)
- @mutex.synchronize { !@endpoints.add?(remote_path) }
+ def parse_gem(line)
+ @dependency_parser ||= GemParser.new
+ @dependency_parser.parse(line)
end
- def read(path)
- return unless path.file?
- SharedHelpers.filesystem_access(path, :read, &:read)
+ def info_roots
+ [
+ directory.join("info"),
+ directory.join("info-special-characters"),
+ ]
end
end
end
diff --git a/lib/bundler/compact_index_client/cache_file.rb b/lib/bundler/compact_index_client/cache_file.rb
deleted file mode 100644
index 5988bc91b3..0000000000
--- a/lib/bundler/compact_index_client/cache_file.rb
+++ /dev/null
@@ -1,153 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../vendored_fileutils"
-require "rubygems/package"
-
-module Bundler
- class CompactIndexClient
- # write cache files in a way that is robust to concurrent modifications
- # if digests are given, the checksums will be verified
- class CacheFile
- DEFAULT_FILE_MODE = 0o644
- private_constant :DEFAULT_FILE_MODE
-
- class Error < RuntimeError; end
- class ClosedError < Error; end
-
- class DigestMismatchError < Error
- def initialize(digests, expected_digests)
- super "Calculated checksums #{digests.inspect} did not match expected #{expected_digests.inspect}."
- end
- end
-
- # Initialize with a copy of the original file, then yield the instance.
- def self.copy(path, &block)
- new(path) do |file|
- file.initialize_digests
-
- SharedHelpers.filesystem_access(path, :read) do
- path.open("rb") do |s|
- file.open {|f| IO.copy_stream(s, f) }
- end
- end
-
- yield file
- end
- end
-
- # Write data to a temp file, then replace the original file with it verifying the digests if given.
- def self.write(path, data, digests = nil)
- return unless data
- new(path) do |file|
- file.digests = digests
- file.write(data)
- end
- end
-
- attr_reader :original_path, :path
-
- def initialize(original_path, &block)
- @original_path = original_path
- @perm = original_path.file? ? original_path.stat.mode : DEFAULT_FILE_MODE
- @path = original_path.sub(/$/, ".#{$$}.tmp")
- return unless block_given?
- begin
- yield self
- ensure
- close
- end
- end
-
- def size
- path.size
- end
-
- # initialize the digests using CompactIndexClient::SUPPORTED_DIGESTS, or a subset based on keys.
- def initialize_digests(keys = nil)
- @digests = keys ? SUPPORTED_DIGESTS.slice(*keys) : SUPPORTED_DIGESTS.dup
- @digests.transform_values! {|algo_class| SharedHelpers.digest(algo_class).new }
- end
-
- # reset the digests so they don't contain any previously read data
- def reset_digests
- @digests&.each_value(&:reset)
- end
-
- # set the digests that will be verified at the end
- def digests=(expected_digests)
- @expected_digests = expected_digests
-
- if @expected_digests.nil?
- @digests = nil
- elsif @digests
- @digests = @digests.slice(*@expected_digests.keys)
- else
- initialize_digests(@expected_digests.keys)
- end
- end
-
- # remove this method when we stop generating md5 digests for legacy etags
- def md5
- @digests && @digests["md5"]
- end
-
- def digests?
- @digests&.any?
- end
-
- # Open the temp file for writing, reusing original permissions, yielding the IO object.
- def open(write_mode = "wb", perm = @perm, &block)
- raise ClosedError, "Cannot reopen closed file" if @closed
- SharedHelpers.filesystem_access(path, :write) do
- path.open(write_mode, perm) do |f|
- yield digests? ? Gem::Package::DigestIO.new(f, @digests) : f
- end
- end
- end
-
- # Returns false without appending when no digests since appending is too error prone to do without digests.
- def append(data)
- return false unless digests?
- open("a") {|f| f.write data }
- verify && commit
- end
-
- def write(data)
- reset_digests
- open {|f| f.write data }
- commit!
- end
-
- def commit!
- verify || raise(DigestMismatchError.new(@base64digests, @expected_digests))
- commit
- end
-
- # Verify the digests, returning true on match, false on mismatch.
- def verify
- return true unless @expected_digests && digests?
- @base64digests = @digests.transform_values!(&:base64digest)
- @digests = nil
- @base64digests.all? {|algo, digest| @expected_digests[algo] == digest }
- end
-
- # Replace the original file with the temp file without verifying digests.
- # The file is permanently closed.
- def commit
- raise ClosedError, "Cannot commit closed file" if @closed
- SharedHelpers.filesystem_access(original_path, :write) do
- FileUtils.mv(path, original_path)
- end
- @closed = true
- end
-
- # Remove the temp file without replacing the original file.
- # The file is permanently closed.
- def close
- return if @closed
- FileUtils.remove_file(path) if @path&.file?
- @closed = true
- end
- end
- 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/parser.rb b/lib/bundler/compact_index_client/parser.rb
deleted file mode 100644
index 3276abdd68..0000000000
--- a/lib/bundler/compact_index_client/parser.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class CompactIndexClient
- class Parser
- # `compact_index` - an object responding to #names, #versions, #info(name, checksum),
- # returning the file contents as a string
- def initialize(compact_index)
- @compact_index = compact_index
- @info_checksums = nil
- @versions_by_name = nil
- @available = nil
- @gem_parser = nil
- end
-
- def names
- lines(@compact_index.names)
- end
-
- def versions
- @versions_by_name ||= Hash.new {|hash, key| hash[key] = [] }
- @info_checksums = {}
-
- lines(@compact_index.versions).each do |line|
- name, versions_string, checksum = line.split(" ", 3)
- @info_checksums[name] = checksum || ""
- versions_string.split(",") do |version|
- delete = version.delete_prefix!("-")
- version = version.split("-", 2).unshift(name)
- if delete
- @versions_by_name[name].delete(version)
- else
- @versions_by_name[name] << version
- end
- end
- end
-
- @versions_by_name
- end
-
- def info(name)
- data = @compact_index.info(name, info_checksums[name])
- lines(data).map {|line| gem_parser.parse(line).unshift(name) }
- end
-
- def available?
- return @available unless @available.nil?
- @available = !info_checksums.empty?
- end
-
- private
-
- def info_checksums
- @info_checksums ||= lines(@compact_index.versions).each_with_object({}) do |line, checksums|
- parse_version_checksum(line, checksums)
- end
- end
-
- def lines(data)
- return [] if data.nil? || data.empty?
- lines = data.split("\n")
- header = lines.index("---")
- header ? lines[header + 1..-1] : lines
- end
-
- def gem_parser
- @gem_parser ||= GemParser.new
- end
-
- # This is mostly the same as `split(" ", 3)` but it avoids allocating extra objects.
- # This method gets called at least once for every gem when parsing versions.
- def parse_version_checksum(line, checksums)
- return unless (name_end = line.index(" ")) # Artifactory bug causes blank lines in artifactor index files
- return unless (checksum_start = line.index(" ", name_end + 1) + 1)
- checksum_end = line.size - checksum_start
-
- line.freeze # allows slicing into the string to not allocate a copy of the line
- name = line[0, name_end]
- checksum = line[checksum_start, checksum_end]
- checksums[name.freeze] = checksum # freeze name since it is used as a hash key
- end
- end
- end
-end
diff --git a/lib/bundler/compact_index_client/updater.rb b/lib/bundler/compact_index_client/updater.rb
index 36f6b81db8..0f7bf9bb50 100644
--- a/lib/bundler/compact_index_client/updater.rb
+++ b/lib/bundler/compact_index_client/updater.rb
@@ -1,11 +1,20 @@
# frozen_string_literal: true
+require_relative "../vendored_fileutils"
+
module Bundler
class CompactIndexClient
class Updater
- class MismatchedChecksumError < Error
- def initialize(path, message)
- super "The checksum of /#{path} does not match the checksum provided by the server! Something is wrong. #{message}"
+ class MisMatchedChecksumError < Error
+ def initialize(path, server_checksum, local_checksum)
+ @path = path
+ @server_checksum = server_checksum
+ @local_checksum = local_checksum
+ end
+
+ def message
+ "The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \
+ "(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})."
end
end
@@ -13,102 +22,95 @@ module Bundler
@fetcher = fetcher
end
- def update(remote_path, local_path, etag_path)
- append(remote_path, local_path, etag_path) || replace(remote_path, local_path, etag_path)
- rescue CacheFile::DigestMismatchError => e
- raise MismatchedChecksumError.new(remote_path, e.message)
- rescue Zlib::GzipFile::Error
- raise Bundler::HTTPError
- end
+ def update(local_path, remote_path, retrying = nil)
+ headers = {}
- private
+ local_temp_path = local_path.sub(/$/, ".#{$$}")
+ local_temp_path = local_temp_path.sub(/$/, ".retrying") if retrying
+ local_temp_path = local_temp_path.sub(/$/, ".tmp")
+
+ # first try to fetch any new bytes on the existing file
+ if retrying.nil? && local_path.file?
+ copy_file local_path, local_temp_path
+
+ headers["If-None-Match"] = etag_for(local_temp_path)
+ headers["Range"] =
+ if local_temp_path.size.nonzero?
+ # Subtract a byte to ensure the range won't be empty.
+ # Avoids 416 (Range Not Satisfiable) responses.
+ "bytes=#{local_temp_path.size - 1}-"
+ else
+ "bytes=#{local_temp_path.size}-"
+ end
+ end
- def append(remote_path, local_path, etag_path)
- return false unless local_path.file? && local_path.size.nonzero?
+ response = @fetcher.call(remote_path, headers)
+ return nil if response.is_a?(Net::HTTPNotModified)
- CacheFile.copy(local_path) do |file|
- etag = etag_path.read.tap(&:chomp!) if etag_path.file?
- etag ||= generate_etag(etag_path, file) # Remove this after 2.5.0 has been out for a while.
+ content = response.body
- # Subtract a byte to ensure the range won't be empty.
- # Avoids 416 (Range Not Satisfiable) responses.
- response = @fetcher.call(remote_path, request_headers(etag, file.size - 1))
- break true if response.is_a?(Gem::Net::HTTPNotModified)
+ etag = (response["ETag"] || "").gsub(%r{\AW/}, "")
+ correct_response = SharedHelpers.filesystem_access(local_temp_path) do
+ if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero?
+ local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) }
- file.digests = parse_digests(response)
- # server may ignore Range and return the full response
- if response.is_a?(Gem::Net::HTTPPartialContent)
- break false unless file.append(response.body.byteslice(1..-1))
+ etag_for(local_temp_path) == etag
else
- file.write(response.body)
+ local_temp_path.open("wb") {|f| f << content }
+
+ etag.length.zero? || etag_for(local_temp_path) == etag
end
- CacheFile.write(etag_path, etag_from_response(response))
- true
end
- end
- # request without range header to get the full file or a 304 Not Modified
- def replace(remote_path, local_path, etag_path)
- etag = etag_path.read.tap(&:chomp!) if etag_path.file?
- response = @fetcher.call(remote_path, request_headers(etag))
- return true if response.is_a?(Gem::Net::HTTPNotModified)
- CacheFile.write(local_path, response.body, parse_digests(response))
- CacheFile.write(etag_path, etag_from_response(response))
- end
+ if correct_response
+ SharedHelpers.filesystem_access(local_path) do
+ FileUtils.mv(local_temp_path, local_path)
+ end
+ return nil
+ end
- def request_headers(etag, range_start = nil)
- headers = {}
- headers["Range"] = "bytes=#{range_start}-" if range_start
- headers["If-None-Match"] = %("#{etag}") if etag
- headers
- end
+ if retrying
+ raise MisMatchedChecksumError.new(remote_path, etag, etag_for(local_temp_path))
+ end
- def etag_for_request(etag_path)
- etag_path.read.tap(&:chomp!) if etag_path.file?
+ update(local_path, remote_path, :retrying)
+ rescue Zlib::GzipFile::Error
+ raise Bundler::HTTPError
+ ensure
+ FileUtils.remove_file(local_temp_path) if File.exist?(local_temp_path)
end
- # When first releasing this opaque etag feature, we want to generate the old MD5 etag
- # based on the content of the file. After that it will always use the saved opaque etag.
- # This transparently saves existing users with good caches from updating a bunch of files.
- # Remove this behavior after 2.5.0 has been out for a while.
- def generate_etag(etag_path, file)
- etag = file.md5.hexdigest
- CacheFile.write(etag_path, etag)
- etag
+ def etag_for(path)
+ sum = checksum_for_file(path)
+ sum ? %("#{sum}") : nil
end
- def etag_from_response(response)
- return unless response["ETag"]
- etag = response["ETag"].delete_prefix("W/")
- return if etag.delete_prefix!('"') && !etag.delete_suffix!('"')
- etag
+ def slice_body(body, range)
+ body.byteslice(range)
end
- # Unwraps and returns a Hash of digest algorithms and base64 values
- # according to RFC 8941 Structured Field Values for HTTP.
- # https://www.rfc-editor.org/rfc/rfc8941#name-parsing-a-byte-sequence
- # Ignores unsupported algorithms.
- def parse_digests(response)
- return unless header = response["Repr-Digest"] || response["Digest"]
- digests = {}
- header.split(",") do |param|
- algorithm, value = param.split("=", 2)
- algorithm.strip!
- algorithm.downcase!
- next unless SUPPORTED_DIGESTS.key?(algorithm)
- next unless value = byte_sequence(value)
- digests[algorithm] = value
+ def checksum_for_file(path)
+ return nil unless path.file?
+ # This must use File.read instead of Digest.file().hexdigest
+ # because we need to preserve \n line endings on windows when calculating
+ # the checksum
+ SharedHelpers.filesystem_access(path, :read) do
+ SharedHelpers.digest(:MD5).hexdigest(File.read(path))
end
- digests.empty? ? nil : digests
end
- # Unwrap surrounding colons (byte sequence)
- # The wrapping characters must be matched or we return nil.
- # Also handles quotes because right now rubygems.org sends them.
- def byte_sequence(value)
- return if value.delete_prefix!(":") && !value.delete_suffix!(":")
- return if value.delete_prefix!('"') && !value.delete_suffix!('"')
- value
+ private
+
+ def copy_file(source, dest)
+ SharedHelpers.filesystem_access(source, :read) do
+ File.open(source, "r") do |s|
+ SharedHelpers.filesystem_access(dest, :write) do
+ File.open(dest, "wb", s.stat.mode) do |f|
+ IO.copy_stream(s, f)
+ end
+ end
+ end
+ end
end
end
end
diff --git a/lib/bundler/constants.rb b/lib/bundler/constants.rb
index 9564771e78..8dd8a53815 100644
--- a/lib/bundler/constants.rb
+++ b/lib/bundler/constants.rb
@@ -1,14 +1,7 @@
# frozen_string_literal: true
-require "rbconfig"
-
module Bundler
WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/
- deprecate_constant :WINDOWS
-
FREEBSD = RbConfig::CONFIG["host_os"].to_s.include?("bsd")
- deprecate_constant :FREEBSD
-
- NULL = File::NULL
- deprecate_constant :NULL
+ NULL = WINDOWS ? "NUL" : "/dev/null"
end
diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb
index 93e0c401c0..f9987c4da8 100644
--- a/lib/bundler/current_ruby.rb
+++ b/lib/bundler/current_ruby.rb
@@ -22,8 +22,6 @@ module Bundler
2.7
3.0
3.1
- 3.2
- 3.3
].freeze
KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze
@@ -43,7 +41,7 @@ module Bundler
].freeze
def ruby?
- return true if Bundler::GemHelpers.generic_local_platform_is_ruby?
+ return true if Bundler::GemHelpers.generic_local_platform == Gem::Platform::RUBY
!windows? && (RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby")
end
@@ -71,10 +69,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 e7e6c49e6c..e27374f35d 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -18,8 +18,7 @@ module Bundler
:platforms,
:ruby_version,
:lockfile,
- :gemfiles,
- :locked_checksums
+ :gemfiles
)
# Given a gemfile and lockfile creates a Bundler definition
@@ -69,6 +68,7 @@ module Bundler
@sources = sources
@unlock = unlock
@optional_groups = optional_groups
+ @remote = false
@prefer_local = false
@specs = nil
@ruby_version = ruby_version
@@ -76,27 +76,22 @@ module Bundler
@lockfile = lockfile
@lockfile_contents = String.new
-
@locked_bundler_version = nil
- @resolved_bundler_version = nil
-
- @locked_ruby_version = nil
- @new_platforms = []
+ @locked_ruby_version = nil
+ @new_platform = nil
@removed_platform = nil
- if lockfile_exists?
+ if lockfile && File.exist?(lockfile)
@lockfile_contents = Bundler.read_file(lockfile)
@locked_gems = LockfileParser.new(@lockfile_contents)
@locked_platforms = @locked_gems.platforms
@platforms = @locked_platforms.dup
@locked_bundler_version = @locked_gems.bundler_version
@locked_ruby_version = @locked_gems.ruby_version
- @originally_locked_deps = @locked_gems.dependencies
@originally_locked_specs = SpecSet.new(@locked_gems.specs)
- @locked_checksums = @locked_gems.checksums
if unlock != true
- @locked_deps = @originally_locked_deps
+ @locked_deps = @locked_gems.dependencies
@locked_specs = @originally_locked_specs
@locked_sources = @locked_gems.sources
else
@@ -111,11 +106,9 @@ module Bundler
@locked_gems = nil
@locked_deps = {}
@locked_specs = SpecSet.new([])
- @originally_locked_deps = {}
@originally_locked_specs = @locked_specs
@locked_sources = []
@locked_platforms = []
- @locked_checksums = Bundler.feature_flag.bundler_3_mode?
end
locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
@@ -131,31 +124,29 @@ module Bundler
@sources.merged_gem_lockfile_sections!(locked_gem_sources.first)
end
- @sources_to_unlock = @unlock.delete(:sources) || []
+ @unlock[:sources] ||= []
@unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
@ruby_version.diff(locked_ruby_version_object)
end
@unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
- @current_platform_missing = add_current_platform unless Bundler.frozen_bundle?
+ add_current_platform unless Bundler.frozen_bundle?
converge_path_sources_to_gemspec_sources
@path_changes = converge_paths
@source_changes = converge_sources
- @explicit_unlocks = @unlock.delete(:gems) || []
-
if @unlock[:conservative]
- @gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
+ @unlock[:gems] ||= @dependencies.map(&:name)
else
- eager_unlock = @explicit_unlocks.map {|name| Dependency.new(name, ">= 0") }
- @gems_to_unlock = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
+ eager_unlock = (@unlock[:gems] || []).map {|name| Dependency.new(name, ">= 0") }
+ @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
end
@dependency_changes = converge_dependencies
@local_changes = converge_locals
- check_lockfile
+ @incomplete_lockfile = check_missing_lockfile_specs
end
def gem_version_promoter
@@ -163,24 +154,37 @@ module Bundler
end
def resolve_only_locally!
+ @remote = false
sources.local_only!
resolve
end
def resolve_with_cache!
- sources.local!
sources.cached!
resolve
end
def resolve_remotely!
- sources.cached!
+ @remote = true
sources.remote!
resolve
end
- def prefer_local!
- @prefer_local = true
+ def resolution_mode=(options)
+ if options["local"]
+ @remote = false
+ else
+ @remote = true
+ @prefer_local = options["prefer-local"]
+ end
+ end
+
+ def setup_sources_for_resolve
+ if @remote == false
+ sources.cached!
+ else
+ sources.remote!
+ end
end
# For given dependency list returns a SpecSet with Gemspec of all the required
@@ -213,9 +217,8 @@ module Bundler
rescue BundlerError => e
@resolve = nil
@resolver = nil
- @resolution_packages = nil
- @source_requirements = nil
@specs = nil
+ @gem_version_promoter = nil
Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
true
@@ -230,17 +233,8 @@ module Bundler
end
def current_dependencies
- filter_relevant(dependencies)
- end
-
- def current_locked_dependencies
- filter_relevant(locked_dependencies)
- end
-
- def filter_relevant(dependencies)
- platforms_array = [generic_local_platform].freeze
dependencies.select do |d|
- d.should_include? && !d.gem_platforms(platforms_array).empty?
+ d.should_include? && !d.gem_platforms([generic_local_platform]).empty?
end
end
@@ -264,15 +258,9 @@ module Bundler
def dependencies_for(groups)
groups.map!(&:to_sym)
- deps = current_dependencies # always returns a new array
- deps.select! do |d|
- if RUBY_VERSION >= "3.1"
- d.groups.intersect?(groups)
- else
- !(d.groups & groups).empty?
- end
+ current_dependencies.reject do |d|
+ (d.groups & groups).empty?
end
- deps
end
# Resolve all the dependencies specified in Gemfile. It ensures that
@@ -284,7 +272,7 @@ module Bundler
@resolve ||= if Bundler.frozen_bundle?
Bundler.ui.debug "Frozen, using resolution from the lockfile"
@locked_specs
- elsif no_resolve_needed?
+ elsif !unlocking? && nothing_changed?
if deleted_deps.any?
Bundler.ui.debug "Some dependencies were deleted, using a subset of the resolution from the lockfile"
SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps))
@@ -297,12 +285,7 @@ module Bundler
end
end
else
- if lockfile_exists?
- Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}"
- else
- Bundler.ui.debug "Resolving dependencies because there's no lockfile"
- end
-
+ Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}"
start_resolution
end
end
@@ -315,26 +298,34 @@ module Bundler
dependencies.map(&:groups).flatten.uniq
end
- def lock(file_or_preserve_unknown_sections = false, preserve_unknown_sections_or_unused = false)
- if [true, false, nil].include?(file_or_preserve_unknown_sections)
- target_lockfile = lockfile
- preserve_unknown_sections = file_or_preserve_unknown_sections
- else
- target_lockfile = file_or_preserve_unknown_sections
- preserve_unknown_sections = preserve_unknown_sections_or_unused
+ def lock(file, preserve_unknown_sections = false)
+ return if Definition.no_lock
- suggestion = if target_lockfile == lockfile
- "To fix this warning, remove it from the `Definition#lock` call."
- else
- "Instead, instantiate a new definition passing `#{target_lockfile}`, and call `lock` without a file argument on that definition"
- end
+ contents = to_lock
+
+ # Convert to \r\n if the existing lock has them
+ # i.e., Windows with `git config core.autocrlf=true`
+ contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match?("\r\n")
- msg = "`Definition#lock` was passed a target file argument. #{suggestion}"
+ if @locked_bundler_version
+ locked_major = @locked_bundler_version.segments.first
+ current_major = Bundler.gem_version.segments.first
- Bundler::SharedHelpers.major_deprecation 2, msg
+ updating_major = locked_major < current_major
+ end
+
+ preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
+
+ return if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
+
+ if Bundler.frozen_bundle?
+ Bundler.ui.error "Cannot write a changed lockfile while frozen."
+ return
end
- write_lock(target_lockfile, preserve_unknown_sections)
+ SharedHelpers.filesystem_access(file) do |p|
+ File.open(p, "wb") {|f| f.puts(contents) }
+ end
end
def locked_ruby_version
@@ -358,19 +349,26 @@ module Bundler
end
end
- def bundler_version_to_lock
- @resolved_bundler_version || Bundler.gem_version
- end
-
def to_lock
require_relative "lockfile_generator"
LockfileGenerator.generate(self)
end
def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
- return unless Bundler.frozen_bundle?
+ msg = String.new
+ msg << "You are trying to install in deployment mode after changing\n" \
+ "your Gemfile. Run `bundle install` elsewhere and add the\n" \
+ "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control."
- raise ProductionError, "Frozen mode is set, but there's no lockfile" unless lockfile_exists?
+ unless explicit_flag
+ suggested_command = if Bundler.settings.locations("frozen").keys.&([:global, :local]).any?
+ "bundle config unset frozen"
+ elsif Bundler.settings.locations("deployment").keys.&([:global, :local]).any?
+ "bundle config unset deployment"
+ end
+ msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \
+ "freeze \nby running `#{suggested_command}`." if suggested_command
+ end
added = []
deleted = []
@@ -385,36 +383,32 @@ module Bundler
deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any?
both_sources = Hash.new {|h, k| h[k] = [] }
- current_dependencies.each {|d| both_sources[d.name][0] = d }
- current_locked_dependencies.each {|d| both_sources[d.name][1] = d }
+ @dependencies.each {|d| both_sources[d.name][0] = d }
+
+ locked_dependencies.each do |d|
+ next if !Bundler.feature_flag.bundler_3_mode? && @locked_specs[d.name].empty?
+
+ both_sources[d.name][1] = d
+ end
both_sources.each do |name, (dep, lock_dep)|
next if dep.nil? || lock_dep.nil?
- gemfile_source = dep.source || default_source
- lock_source = lock_dep.source || default_source
+ gemfile_source = dep.source || sources.default_source
+ lock_source = lock_dep.source || sources.default_source
next if lock_source.include?(gemfile_source)
- gemfile_source_name = dep.source ? gemfile_source.to_gemfile : "no specified source"
- lockfile_source_name = lock_dep.source ? lock_source.to_gemfile : "no specified source"
+ gemfile_source_name = dep.source ? gemfile_source.identifier : "no specified source"
+ lockfile_source_name = lock_dep.source ? lock_source.identifier : "no specified source"
changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
end
- reason = nothing_changed? ? "some dependencies were deleted from your gemfile" : change_reason
- msg = String.new
- msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because frozen mode is set"
+ reason = change_reason
+ msg << "\n\n#{reason.split(", ").map(&:capitalize).join("\n")}" unless reason.strip.empty?
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"
-
- 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} " \
- "freeze by running `#{suggested_command}`." if suggested_command
- end
+ msg << "\n"
raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed?
end
@@ -453,15 +447,13 @@ 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)
- return if @platforms.include?(platform)
-
- @new_platforms << platform
- @platforms << platform
+ @new_platform ||= !@platforms.include?(platform)
+ @platforms |= [platform]
end
def remove_platform(platform)
@@ -477,100 +469,33 @@ module Bundler
end
end
- def nothing_changed?
- return false unless lockfile_exists?
-
- !@source_changes &&
- !@dependency_changes &&
- !@current_platform_missing &&
- @new_platforms.empty? &&
- !@path_changes &&
- !@local_changes &&
- !@missing_lockfile_dep &&
- !@unlocking_bundler &&
- !@locked_spec_with_missing_deps &&
- !@locked_spec_with_invalid_deps
- end
+ attr_reader :sources
+ private :sources
- def no_resolve_needed?
- !unlocking? && nothing_changed?
+ def nothing_changed?
+ !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@incomplete_lockfile
end
def unlocking?
@unlocking
end
- attr_writer :source_requirements
-
private
- attr_reader :sources
-
- def should_add_extra_platforms?
- !lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform]
- end
-
- def lockfile_exists?
- lockfile && File.exist?(lockfile)
- end
-
- def write_lock(file, preserve_unknown_sections)
- return if Definition.no_lock || file.nil?
-
- contents = to_lock
-
- # Convert to \r\n if the existing lock has them
- # i.e., Windows with `git config core.autocrlf=true`
- contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match?("\r\n")
-
- if @locked_bundler_version
- locked_major = @locked_bundler_version.segments.first
- current_major = bundler_version_to_lock.segments.first
-
- updating_major = locked_major < current_major
- end
-
- preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
-
- if File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
- return if Bundler.frozen_bundle?
- SharedHelpers.filesystem_access(file) { FileUtils.touch(file) }
- return
- end
-
- if Bundler.frozen_bundle?
- Bundler.ui.error "Cannot write a changed lockfile while frozen."
- return
- end
-
- SharedHelpers.filesystem_access(file) do |p|
- File.open(p, "wb") {|f| f.puts(contents) }
- end
- end
-
def resolver
@resolver ||= Resolver.new(resolution_packages, gem_version_promoter)
end
def expanded_dependencies
- dependencies_with_bundler + metadata_dependencies
- end
-
- def dependencies_with_bundler
- return dependencies unless @unlocking_bundler
- return dependencies if dependencies.map(&:name).include?("bundler")
-
- [Dependency.new("bundler", @unlocking_bundler)] + dependencies
+ dependencies + metadata_dependencies
end
def resolution_packages
@resolution_packages ||= begin
last_resolve = converge_locked_specs
- remove_invalid_platforms!
- packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @gems_to_unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local)
- packages = additional_base_requirements_to_prevent_downgrades(packages, last_resolve)
- packages = additional_base_requirements_to_force_updates(packages)
- packages
+ 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
end
@@ -585,7 +510,7 @@ module Bundler
if missing_specs.any?
missing_specs.each do |s|
locked_gem = @locked_specs[s.name].last
- next if locked_gem.nil? || locked_gem.version != s.version || sources.local_mode?
+ next if locked_gem.nil? || locked_gem.version != s.version || !@remote
raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
"no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
"You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
@@ -604,7 +529,7 @@ module Bundler
break if incomplete_specs.empty?
Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
- sources.remote!
+ setup_sources_for_resolve
resolution_packages.delete(incomplete_specs)
@resolve = start_resolution
specs = resolve.materialize(dependencies)
@@ -626,80 +551,66 @@ module Bundler
end
def start_resolution
- local_platform_needed_for_resolvability = @most_specific_non_local_locked_ruby_platform && !@platforms.include?(local_platform)
- @platforms << local_platform if local_platform_needed_for_resolvability
- add_platform(Gem::Platform::RUBY) if RUBY_ENGINE == "truffleruby"
+ result = resolver.start
+
+ SpecSet.new(SpecSet.new(result).for(dependencies, false, @platforms))
+ end
- result = SpecSet.new(resolver.start)
+ def precompute_source_requirements_for_indirect_dependencies?
+ sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
+ end
- @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version
+ def pin_locally_available_names(source_requirements)
+ source_requirements.each_with_object({}) do |(name, original_source), new_source_requirements|
+ local_source = original_source.dup
+ local_source.local_only!
- if @most_specific_non_local_locked_ruby_platform
- if spec_set_incomplete_for_platform?(result, @most_specific_non_local_locked_ruby_platform)
- @platforms.delete(@most_specific_non_local_locked_ruby_platform)
- elsif local_platform_needed_for_resolvability
- @platforms.delete(local_platform)
+ new_source_requirements[name] = if local_source.specs.search(name).any?
+ local_source
+ else
+ original_source
end
end
-
- @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
-
- SpecSet.new(result.for(dependencies, false, @platforms))
end
- def precompute_source_requirements_for_indirect_dependencies?
- sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
+ def current_ruby_platform_locked?
+ return false unless generic_local_platform == Gem::Platform::RUBY
+ return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY)
+
+ current_platform_locked?
end
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
def add_current_platform
- return if @platforms.include?(local_platform)
-
- @most_specific_non_local_locked_ruby_platform = find_most_specific_locked_ruby_platform
- return if @most_specific_non_local_locked_ruby_platform
-
- @platforms << local_platform
- true
- end
-
- def find_most_specific_locked_ruby_platform
- return unless generic_local_platform_is_ruby? && current_platform_locked?
+ return if current_ruby_platform_locked?
- most_specific_locked_platform
+ add_platform(local_platform)
end
def change_reason
if unlocking?
- unlock_targets = if @gems_to_unlock.any?
- ["gems", @gems_to_unlock]
- elsif @sources_to_unlock.any?
- ["sources", @sources_to_unlock]
- end
-
- unlock_reason = if unlock_targets
- "#{unlock_targets.first}: (#{unlock_targets.last.join(", ")})"
- else
- @unlock[:ruby] ? "ruby" : ""
- end
-
+ unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v|
+ if v == true
+ k.to_s
+ else
+ v = Array(v)
+ "#{k}: (#{v.join(", ")})"
+ end
+ end.join(", ")
return "bundler is unlocking #{unlock_reason}"
end
[
[@source_changes, "the list of sources changed"],
[@dependency_changes, "the dependencies in your gemfile changed"],
- [@current_platform_missing, "your lockfile does not include the current platform"],
- [@new_platforms.any?, "you added a new platform to your gemfile"],
+ [@new_platform, "you added a new platform to your gemfile"],
[@path_changes, "the gemspecs for path gems changed"],
[@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"],
- [@locked_spec_with_missing_deps, "your lock file includes \"#{@locked_spec_with_missing_deps}\" but not some of its dependencies"],
- [@locked_spec_with_invalid_deps, "your lockfile does not satisfy dependencies of \"#{@locked_spec_with_invalid_deps}\""],
+ [@incomplete_lockfile, "your lock file is missing some gems"],
].select(&:first).map(&:last).join(", ")
end
@@ -726,7 +637,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
@@ -740,9 +652,9 @@ module Bundler
Bundler.settings.local_overrides.map do |k, v|
spec = @dependencies.find {|s| s.name == k }
- source = spec&.source
- if source&.respond_to?(:local_override!)
- source.unlock! if @gems_to_unlock.include?(spec.name)
+ source = spec && spec.source
+ if source && source.respond_to?(:local_override!)
+ source.unlock! if @unlock[:gems].include?(spec.name)
locals << [source, source.local_override!(v)]
end
end
@@ -750,39 +662,14 @@ module Bundler
sources_with_changes = locals.select do |source, changed|
changed || specs_changed?(source)
end.map(&:first)
- !sources_with_changes.each {|source| @sources_to_unlock << source.name }.empty?
+ !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty?
end
- def check_lockfile
- @missing_lockfile_dep = nil
-
- @locked_spec_with_invalid_deps = nil
- @locked_spec_with_missing_deps = nil
-
- missing = []
- invalid = []
-
- @locked_specs.each do |s|
- validation = @locked_specs.validate_deps(s)
+ def check_missing_lockfile_specs
+ all_locked_specs = @locked_specs.map(&:name) << "bundler"
- missing << s if validation == :missing
- invalid << s if validation == :invalid
- end
-
- if missing.any?
- @locked_specs.delete(missing)
-
- @locked_spec_with_missing_deps = missing.first.name
- elsif !@dependency_changes
- @missing_lockfile_dep = current_dependencies.find do |d|
- @locked_specs[d.name].empty? && d.name != "bundler"
- end&.name
- end
-
- if invalid.any?
- @locked_specs.delete(invalid)
-
- @locked_spec_with_invalid_deps = invalid.first.name
+ @locked_specs.any? do |s|
+ s.dependencies.any? {|dep| !all_locked_specs.include?(dep.name) }
end
end
@@ -817,17 +704,12 @@ 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_checksums && @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
# will cause the `ref` used to be the most recent for the branch (or master) if
# an explicit `ref` is not used.
- if source.respond_to?(:unlock!) && @sources_to_unlock.include?(source.name)
+ if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
source.unlock!
changes = true
end
@@ -844,7 +726,7 @@ module Bundler
dep.source = sources.get(dep.source)
end
- unless locked_dep = @originally_locked_deps[dep.name]
+ unless locked_dep = @locked_deps[dep.name]
changes = true
next
end
@@ -871,7 +753,7 @@ module Bundler
def converge_locked_specs
converged = converge_specs(@locked_specs)
- resolve = SpecSet.new(converged.reject {|s| @gems_to_unlock.include?(s.name) })
+ resolve = SpecSet.new(converged.reject {|s| @unlock[:gems].include?(s.name) })
diff = nil
@@ -890,38 +772,37 @@ module Bundler
def converge_specs(specs)
converged = []
- deps = []
+
+ deps = @dependencies.select do |dep|
+ specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
+ end
@specs_that_changed_sources = []
specs.each do |s|
- name = s.name
dep = @dependencies.find {|d| s.satisfies?(d) }
- lockfile_source = s.source
- if dep
- gemfile_source = dep.source || default_source
+ # Replace the locked dependency's source with the equivalent source from the Gemfile
+ s.source = if dep && dep.source
+ gemfile_source = dep.source
+ lockfile_source = s.source
@specs_that_changed_sources << s if gemfile_source != lockfile_source
- deps << dep if !dep.source || lockfile_source.include?(dep.source)
- @gems_to_unlock << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
- # Replace the locked dependency's source with the equivalent source from the Gemfile
- s.source = gemfile_source
+ gemfile_source
else
- # Replace the locked dependency's source with the default source, if the locked source is no longer in the Gemfile
- s.source = default_source unless sources.get(lockfile_source)
+ sources.get_with_fallback(s.source)
end
- next if @sources_to_unlock.include?(s.source.name)
+ next if @unlock[:sources].include?(s.source.name)
# Path sources have special logic
if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
new_specs = begin
s.source.specs
- rescue PathError
+ rescue PathError, GitError
# if we won't need the source (according to the lockfile),
- # don't error if the path source isn't available
+ # don't error if the path/git source isn't available
next if specs.
for(requested_dependencies, false).
none? {|locked_spec| locked_spec.source == s.source }
@@ -935,12 +816,12 @@ module Bundler
else
# If the spec is no longer in the path source, unlock it. This
# commonly happens if the version changed in the gemspec
- @gems_to_unlock << name
+ @unlock[:gems] << s.name
end
end
- if dep.nil? && requested_dependencies.find {|d| name == d.name }
- @gems_to_unlock << s.name
+ if dep.nil? && requested_dependencies.find {|d| s.name == d.name }
+ @unlock[:gems] << s.name
else
converged << s
end
@@ -951,47 +832,32 @@ 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
def source_requirements
- @source_requirements ||= find_source_requirements
- end
-
- def find_source_requirements
# Record the specs available in each gem's source, so that those
# specs will be available later when the resolver knows where to
# look for that gemspec (or its dependencies)
source_requirements = if precompute_source_requirements_for_indirect_dependencies?
all_requirements = source_map.all_requirements
- { default: default_source }.merge(all_requirements)
+ all_requirements = pin_locally_available_names(all_requirements) if @prefer_local
+ { :default => sources.default_source }.merge(all_requirements)
else
- { default: Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
+ { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
end
- source_requirements.merge!(source_map.locked_requirements) if nothing_changed?
+ source_requirements.merge!(source_map.locked_requirements) unless @remote
metadata_dependencies.each do |dep|
source_requirements[dep.name] = sources.metadata_source
end
-
- default_bundler_source = source_requirements["bundler"] || default_source
-
- if @unlocking_bundler
- default_bundler_source.add_dependency_names("bundler")
- else
- source_requirements[:default_bundler] = default_bundler_source
- source_requirements["bundler"] = sources.metadata_source # needs to come last to override
- end
-
+ source_requirements[:default_bundler] = source_requirements["bundler"] || sources.default_source
+ source_requirements["bundler"] = sources.metadata_source # needs to come last to override
verify_changed_sources!
source_requirements
end
- def default_source
- sources.default_source
- end
-
def verify_changed_sources!
@specs_that_changed_sources.each do |s|
if s.source.specs.search(s.name).empty?
@@ -1010,8 +876,7 @@ module Bundler
if preserve_unknown_sections
sections_to_ignore = LockfileParser.sections_to_ignore(@locked_bundler_version)
sections_to_ignore += LockfileParser.unknown_sections_in_lockfile(current)
- sections_to_ignore << LockfileParser::RUBY
- sections_to_ignore << LockfileParser::BUNDLED unless @unlocking_bundler
+ sections_to_ignore += LockfileParser::ENVIRONMENT_VERSION_SECTIONS
pattern = /#{Regexp.union(sections_to_ignore)}\n(\s{2,}.*\n)+/
whitespace_cleanup = /\n{2,}/
current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip
@@ -1020,53 +885,23 @@ module Bundler
current == proposed
end
- def additional_base_requirements_to_prevent_downgrades(resolution_packages, last_resolve)
- return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources)
+ def additional_base_requirements_for_resolve(resolution_packages, last_resolve)
+ return resolution_packages unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources)
converge_specs(@originally_locked_specs - last_resolve).each do |locked_spec|
- next if locked_spec.source.is_a?(Source::Path)
resolution_packages.base_requirements[locked_spec.name] = Gem::Requirement.new(">= #{locked_spec.version}")
end
resolution_packages
end
- def additional_base_requirements_to_force_updates(resolution_packages)
- return resolution_packages if @explicit_unlocks.empty?
- full_update = dup_for_full_unlock.resolve
- @explicit_unlocks.each do |name|
- version = full_update[name].first&.version
- resolution_packages.base_requirements[name] = Gem::Requirement.new("= #{version}") if version
- end
- resolution_packages
- end
-
- def dup_for_full_unlock
- unlocked_definition = self.class.new(@lockfile, @dependencies, @sources, true, @ruby_version, @optional_groups, @gemfiles)
- unlocked_definition.source_requirements = source_requirements
- unlocked_definition.gem_version_promoter.tap do |gvp|
- gvp.level = gem_version_promoter.level
- gvp.strict = gem_version_promoter.strict
- gvp.pre = gem_version_promoter.pre
- end
- unlocked_definition
- end
-
- def remove_invalid_platforms!
- return if Bundler.frozen_bundle?
-
- platforms.reverse_each do |platform|
- next if local_platform == platform ||
- @new_platforms.include?(platform) ||
- @path_changes ||
- @dependency_changes ||
- @locked_spec_with_invalid_deps ||
- !spec_set_incomplete_for_platform?(@originally_locked_specs, platform)
-
- remove_platform(platform)
- end
- end
+ 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) ||
+ !@originally_locked_specs.incomplete_ruby_specs?(dependencies)
- def spec_set_incomplete_for_platform?(spec_set, platform)
- spec_set.incomplete_for_platform?(current_dependencies, platform)
+ 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 2a4f72fe55..1f8b9da2eb 100644
--- a/lib/bundler/dependency.rb
+++ b/lib/bundler/dependency.rb
@@ -7,21 +7,20 @@ require_relative "rubygems_ext"
module Bundler
class Dependency < Gem::Dependency
attr_reader :autorequire
- attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref, :glob
+ attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref
- ALL_RUBY_VERSIONS = (18..27).to_a.concat((30..34).to_a).freeze
+ ALL_RUBY_VERSIONS = ((18..27).to_a + (30..31).to_a).freeze
PLATFORM_MAP = {
- ruby: [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
- mri: [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
- rbx: [Gem::Platform::RUBY],
- 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],
- 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]],
+ :ruby => [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
+ :mri => [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
+ :rbx => [Gem::Platform::RUBY],
+ :truffleruby => [Gem::Platform::RUBY],
+ :jruby => [Gem::Platform::JAVA, [18, 19]],
+ :windows => [Gem::Platform::WINDOWS, 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]],
}.each_with_object({}) do |(platform, spec), hash|
hash[platform] = spec[0]
spec[1]&.each {|version| hash[:"#{platform}_#{version}"] = spec[0] }
@@ -39,7 +38,6 @@ module Bundler
@github = options["github"]
@branch = options["branch"]
@ref = options["ref"]
- @glob = options["glob"]
@platforms = Array(options["platforms"])
@env = options["env"]
@should_include = options.fetch("should_include", true)
@@ -49,13 +47,10 @@ module Bundler
@autorequire = Array(options["require"] || []) if options.key?("require")
end
- RUBY_PLATFORM_ARRAY = [Gem::Platform::RUBY].freeze
- private_constant :RUBY_PLATFORM_ARRAY
-
# Returns the platforms this dependency is valid for, in the same order as
# passed in the `valid_platforms` parameter
def gem_platforms(valid_platforms)
- return RUBY_PLATFORM_ARRAY if force_ruby_platform
+ return [Gem::Platform::RUBY] if force_ruby_platform
return valid_platforms if @platforms.empty?
valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) }
@@ -69,10 +64,6 @@ module Bundler
@should_include && current_env? && current_platform?
end
- def gemspec_dev_dep?
- type == :development
- end
-
def current_env?
return true unless @env
if @env.is_a?(Hash)
diff --git a/lib/bundler/digest.rb b/lib/bundler/digest.rb
index 2c6d971f1b..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
@@ -50,7 +50,7 @@ module Bundler
words.map!.with_index {|word, index| SHA1_MASK & (word + mutated[index]) }
end
- words.pack("N*").unpack1("H*")
+ words.pack("N*").unpack("H*").first
end
private
diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb
index 24a9a7683a..e74158a9f5 100644
--- a/lib/bundler/dsl.rb
+++ b/lib/bundler/dsl.rb
@@ -18,10 +18,9 @@ module Bundler
VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules
platform platforms type source install_if gemfile force_ruby_platform].freeze
- GITHUB_PULL_REQUEST_URL = %r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]+/[A-Za-z0-9_\-\.]+)/pull/(\d+)\z}
- GITLAB_MERGE_REQUEST_URL = %r{\Ahttps://gitlab\.com/([A-Za-z0-9_\-\./]+)/-/merge_requests/(\d+)\z}
+ GITHUB_PULL_REQUEST_URL = %r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]+/[A-Za-z0-9_\-\.]+)/pull/(\d+)\z}.freeze
- attr_reader :gemspecs, :gemfile
+ attr_reader :gemspecs
attr_accessor :dependencies
def initialize
@@ -42,20 +41,20 @@ module Bundler
end
def eval_gemfile(gemfile, contents = nil)
- with_gemfile(gemfile) do |current_gemfile|
- contents ||= Bundler.read_file(current_gemfile)
- instance_eval(contents, current_gemfile, 1)
- rescue GemfileEvalError => e
- message = "There was an error evaluating `#{File.basename current_gemfile}`: #{e.message}"
- raise DSLError.new(message, current_gemfile, e.backtrace, contents)
- rescue GemfileError, InvalidArgumentError, InvalidOption, DeprecatedError, ScriptError => e
- message = "There was an error parsing `#{File.basename current_gemfile}`: #{e.message}"
- raise DSLError.new(message, current_gemfile, e.backtrace, contents)
- rescue StandardError => e
- raise unless e.backtrace_locations.first.path == current_gemfile
- message = "There was an error parsing `#{File.basename current_gemfile}`: #{e.message}"
- raise DSLError.new(message, current_gemfile, e.backtrace, contents)
- end
+ expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile && @gemfile.parent)
+ original_gemfile = @gemfile
+ @gemfile = expanded_gemfile_path
+ @gemfiles << expanded_gemfile_path
+ contents ||= Bundler.read_file(@gemfile.to_s)
+ instance_eval(contents.dup.tap {|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1)
+ rescue Exception => e # rubocop:disable Lint/RescueException
+ message = "There was an error " \
+ "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \
+ "`#{File.basename gemfile.to_s}`: #{e.message}"
+
+ raise DSLError.new(message, gemfile, e.backtrace, contents)
+ ensure
+ @gemfile = original_gemfile
end
def gemspec(opts = nil)
@@ -77,11 +76,11 @@ module Bundler
@gemspecs << spec
- gem spec.name, name: spec.name, path: path, glob: glob
+ gem spec.name, :name => spec.name, :path => path, :glob => glob
group(development_group) do
spec.development_dependencies.each do |dep|
- gem dep.name, *(dep.requirement.as_list + [type: :development])
+ gem dep.name, *(dep.requirement.as_list + [:type => :development])
end
end
when 0
@@ -103,51 +102,39 @@ module Bundler
# if there's already a dependency with this name we try to prefer one
if current = @dependencies.find {|d| d.name == dep.name }
- if current.requirement != dep.requirement
- current_requirement_open = current.requirements_list.include?(">= 0")
+ deleted_dep = @dependencies.delete(current) if current.type == :development
- gemspec_dep = [dep, current].find(&:gemspec_dev_dep?)
- if gemspec_dep
- gemfile_dep = [dep, current].find(&:runtime?)
+ unless deleted_dep
+ if current.requirement != dep.requirement
+ return if dep.type == :development
- unless current_requirement_open
- Bundler.ui.warn "A gemspec development dependency (#{gemspec_dep.name}, #{gemspec_dep.requirement}) is being overridden by a Gemfile dependency (#{gemfile_dep.name}, #{gemfile_dep.requirement}).\n" \
- "This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement\n"
- end
- else
update_prompt = ""
if File.basename(@gemfile) == Injector::INJECTED_GEMS
- if dep.requirements_list.include?(">= 0") && !current_requirement_open
+ if dep.requirements_list.include?(">= 0") && !current.requirements_list.include?(">= 0")
update_prompt = ". Gem already added"
else
update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`"
- update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current_requirement_open
+ update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current.requirements_list.include?(">= 0")
end
end
raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \
- "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \
- "#{update_prompt}"
+ "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \
+ "#{update_prompt}"
+ elsif current.source != dep.source
+ return if dep.type == :development
+ raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
+ "You specified that #{dep.name} (#{dep.requirement}) should come from " \
+ "#{current.source || "an unspecified source"} and #{dep.source}\n"
+ else
+ Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
+ "You should probably keep only one of them.\n" \
+ "Remove any duplicate entries and specify the gem only once.\n" \
+ "While it's not a problem now, it could cause errors if you change the version of one of them later."
end
end
-
- # Always prefer the dependency from the Gemfile
- if current.gemspec_dev_dep?
- @dependencies.delete(current)
- elsif dep.gemspec_dev_dep?
- return
- elsif current.source != dep.source
- raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
- "You specified that #{dep.name} (#{dep.requirement}) should come from " \
- "#{current.source || "an unspecified source"} and #{dep.source}\n"
- else
- Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
- "You should probably keep only one of them.\n" \
- "Remove any duplicate entries and specify the gem only once.\n" \
- "While it's not a problem now, it could cause errors if you change the version of one of them later."
- end
end
@dependencies << dep
@@ -219,7 +206,7 @@ module Bundler
end
def github(repo, options = {})
- raise InvalidArgumentError, "GitHub sources require a block" unless block_given?
+ raise ArgumentError, "GitHub sources require a block" unless block_given?
github_uri = @git_sources["github"].call(repo)
git_options = normalize_hash(options).merge("uri" => github_uri)
git_source = @sources.add_git_source(git_options)
@@ -285,16 +272,6 @@ module Bundler
private
- def with_gemfile(gemfile)
- expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile&.parent)
- original_gemfile = @gemfile
- @gemfile = expanded_gemfile_path
- @gemfiles << expanded_gemfile_path
- yield @gemfile.to_s
- ensure
- @gemfile = original_gemfile
- end
-
def add_git_sources
git_source(:github) do |repo_name|
if repo_name =~ GITHUB_PULL_REQUEST_URL
@@ -319,20 +296,6 @@ module Bundler
repo_name ||= user_name
"https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git"
end
-
- git_source(:gitlab) do |repo_name|
- if repo_name =~ GITLAB_MERGE_REQUEST_URL
- {
- "git" => "https://gitlab.com/#{$1}.git",
- "branch" => nil,
- "ref" => "refs/merge-requests/#{$2}/head",
- "tag" => nil,
- }
- else
- repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
- "https://gitlab.com/#{repo_name}.git"
- end
- end
end
def with_source(source)
@@ -434,11 +397,13 @@ module Bundler
end
def validate_keys(command, opts, valid_keys)
- if opts["branch"] && !(opts["git"] || opts["github"] || (opts.keys & @git_sources.keys.map(&:to_s)).any?)
+ invalid_keys = opts.keys - valid_keys
+
+ git_source = opts.keys & @git_sources.keys.map(&:to_s)
+ if opts["branch"] && !(opts["git"] || opts["github"] || git_source.any?)
raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch)
end
- invalid_keys = opts.keys - valid_keys
return true unless invalid_keys.any?
message = String.new
@@ -457,13 +422,9 @@ module Bundler
def normalize_source(source)
case source
when :gemcutter, :rubygems, :rubyforge
- message =
- "The source :#{source} is deprecated because HTTP requests are insecure.\n" \
- "Please change your source to 'https://rubygems.org' if possible, or 'http://rubygems.org' if not."
- removed_message =
- "The source :#{source} is disallowed because HTTP requests are insecure.\n" \
- "Please change your source to 'https://rubygems.org' if possible, or 'http://rubygems.org' if not."
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
+ Bundler::SharedHelpers.major_deprecation 2, "The source :#{source} is deprecated because HTTP " \
+ "requests are insecure.\nPlease change your source to 'https://" \
+ "rubygems.org' if possible, or 'http://rubygems.org' if not."
"http://rubygems.org"
when String
source
@@ -508,17 +469,10 @@ module Bundler
"should come from that source"
raise GemfileEvalError, msg
else
- message =
- "Your Gemfile contains multiple global sources. " \
+ Bundler::SharedHelpers.major_deprecation 2, "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."
- removed_message =
- "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 error, use " \
- "a block to indicate which gems should come from the secondary source."
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
end
end
@@ -587,23 +541,23 @@ module Bundler
return m unless backtrace && dsl_path && contents
- trace_line = backtrace.find {|l| l.include?(dsl_path) } || trace_line
+ trace_line = backtrace.find {|l| l.include?(dsl_path.to_s) } || trace_line
return m unless trace_line
- line_number = trace_line.split(":")[1].to_i - 1
- return m unless line_number
+ line_numer = trace_line.split(":")[1].to_i - 1
+ return m unless line_numer
lines = contents.lines.to_a
indent = " # "
indicator = indent.tr("#", ">")
- first_line = line_number.zero?
- last_line = (line_number == (lines.count - 1))
+ first_line = line_numer.zero?
+ last_line = (line_numer == (lines.count - 1))
m << "\n"
m << "#{indent}from #{trace_line.gsub(/:in.*$/, "")}\n"
m << "#{indent}-------------------------------------------\n"
- m << "#{indent}#{lines[line_number - 1]}" unless first_line
- m << "#{indicator}#{lines[line_number]}"
- m << "#{indent}#{lines[line_number + 1]}" unless last_line
+ m << "#{indent}#{lines[line_numer - 1]}" unless first_line
+ m << "#{indicator}#{lines[line_numer]}"
+ m << "#{indent}#{lines[line_numer + 1]}" unless last_line
m << "\n" unless m.end_with?("\n")
m << "#{indent}-------------------------------------------\n"
end
@@ -613,7 +567,7 @@ module Bundler
def parse_line_number_from_description
description = self.description
- if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path}):\d+)/
+ if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path.to_s}):\d+)/
trace_line = Regexp.last_match[1]
description = description.sub(/\n.*\n(\.\.\.)? *\^~+$/, "").sub(/#{Regexp.quote trace_line}:\s*/, "").sub("\n", " - ")
end
diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb
index 201818cc33..d315d1cc68 100644
--- a/lib/bundler/endpoint_specification.rb
+++ b/lib/bundler/endpoint_specification.rb
@@ -26,6 +26,10 @@ module Bundler
@platform
end
+ def identifier
+ @__identifier ||= [name, version, platform.to_s]
+ end
+
# needed for standalone, load required_paths from local gemspec
# after the gem is installed
def require_paths
@@ -92,20 +96,9 @@ module Bundler
end
end
- # needed for `bundle fund`
- def metadata
- if @remote_specification
- @remote_specification.metadata
- elsif _local_specification
- _local_specification.metadata
- else
- super
- end
- end
-
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
@@ -136,11 +129,7 @@ module Bundler
next unless v
case k.to_s
when "checksum"
- 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 074bef6edc..8b2e292fd6 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
@@ -120,7 +122,7 @@ module Bundler
specs = Bundler.rubygems.find_name(name)
out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty?
end
- if (exe = caller_locations.last.absolute_path)&.match? %r{(exe|bin)/bundler?\z}
+ if (exe = caller.last.split(":").first) && exe =~ %r{(exe|bin)/bundler?\z}
shebang = File.read(exe).lines.first
shebang.sub!(/^#!\s*/, "")
unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby")
diff --git a/lib/bundler/environment_preserver.rb b/lib/bundler/environment_preserver.rb
index 444ab6fd37..70967522af 100644
--- a/lib/bundler/environment_preserver.rb
+++ b/lib/bundler/environment_preserver.rb
@@ -2,7 +2,7 @@
module Bundler
class EnvironmentPreserver
- INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL"
+ INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL".freeze
BUNDLER_KEYS = %w[
BUNDLE_BIN_PATH
BUNDLE_GEMFILE
@@ -16,10 +16,17 @@ module Bundler
RUBYLIB
RUBYOPT
].map(&:freeze).freeze
- BUNDLER_PREFIX = "BUNDLER_ORIG_"
+ BUNDLER_PREFIX = "BUNDLER_ORIG_".freeze
def self.from_env
- new(ENV.to_hash, BUNDLER_KEYS)
+ new(env_to_hash(ENV), BUNDLER_KEYS)
+ end
+
+ def self.env_to_hash(env)
+ to_hash = env.to_hash
+ return to_hash unless Gem.win_platform?
+
+ to_hash.each_with_object({}) {|(k,v), a| a[k.upcase] = v }
end
# @param env [Hash]
@@ -32,7 +39,18 @@ module Bundler
# Replaces `ENV` with the bundler environment variables backed up
def replace_with_backup
- ENV.replace(backup)
+ unless Gem.win_platform?
+ ENV.replace(backup)
+ return
+ end
+
+ # Fallback logic for Windows below to workaround
+ # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all
+ # supported rubies include the fix for that.
+
+ ENV.clear
+
+ backup.each {|k, v| ENV[k] = v }
end
# @return [Hash]
@@ -40,9 +58,9 @@ module Bundler
env = @original.clone
@keys.each do |key|
value = env[key]
- if !value.nil?
+ if !value.nil? && !value.empty?
env[@prefix + key] ||= value
- else
+ elsif value.nil?
env[@prefix + key] ||= INTENTIONALLY_NIL
end
end
@@ -54,7 +72,7 @@ module Bundler
env = @original.clone
@keys.each do |key|
value_original = env[@prefix + key]
- next if value_original.nil?
+ next if value_original.nil? || value_original.empty?
if value_original == INTENTIONALLY_NIL
env.delete(key)
else
diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb
index a0ce739ad7..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(lock_name, existing, checksum)
- @lock_name = lock_name
- @existing = existing
- @checksum = checksum
- end
-
- def message
- <<~MESSAGE
- Bundler found mismatched checksums. This is a potential security risk.
- #{@lock_name} #{@existing.to_lock}
- from #{@existing.sources.join("\n and ")}
- #{@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,35 +172,4 @@ module Bundler
status_code(36)
end
-
- class InsecureInstallPathError < BundlerError
- def initialize(name, path)
- @name = name
- @path = path
- end
-
- def message
- "Bundler cannot reinstall #{@name} because there's a previous installation of it at #{@path} that is unsafe to remove.\n" \
- "The parent of #{@path} is world-writable and does not have the sticky bit set, making it insecure to remove due to potential vulnerabilities.\n" \
- "Please change the permissions of #{File.dirname(@path)} or choose a different install path."
- end
-
- status_code(38)
- end
-
- class CorruptBundlerInstallError < BundlerError
- def initialize(loaded_spec)
- @loaded_spec = loaded_spec
- end
-
- def message
- "The running version of Bundler (#{Bundler::VERSION}) does not match the version of the specification installed for it (#{@loaded_spec.version}). " \
- "This can be caused by reinstalling Ruby without removing previous installation, leaving around an upgraded default version of Bundler. " \
- "Reinstalling Ruby from scratch should fix the problem."
- end
-
- status_code(39)
- end
-
- class InvalidArgumentError < BundlerError; status_code(40); end
end
diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb
index ab2189f7f0..983de3137c 100644
--- a/lib/bundler/feature_flag.rb
+++ b/lib/bundler/feature_flag.rb
@@ -37,6 +37,7 @@ module Bundler
settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") }
settings_flag(:print_only_version_number) { bundler_3_mode? }
settings_flag(:setup_makes_kernel_gem_public) { !bundler_3_mode? }
+ settings_flag(:suppress_install_using_messages) { bundler_3_mode? }
settings_flag(:update_requires_all_flag) { bundler_4_mode? }
settings_option(:default_cli_command) { bundler_3_mode? ? :cli_help : :install }
diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb
index 14721623f9..a073bae278 100644
--- a/lib/bundler/fetcher.rb
+++ b/lib/bundler/fetcher.rb
@@ -1,15 +1,14 @@
# frozen_string_literal: true
require_relative "vendored_persistent"
-require_relative "vendored_timeout"
require "cgi"
-require_relative "vendored_securerandom"
+require "securerandom"
require "zlib"
+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__)
@@ -62,16 +61,6 @@ module Bundler
end
end
- # This error is raised if HTTP authentication is correct, but lacks
- # necessary permissions.
- class AuthenticationForbiddenError < HTTPError
- def initialize(remote_uri)
- remote_uri = filter_uri(remote_uri)
- super "Access token could not be authenticated for #{remote_uri}.\n" \
- "Make sure it's valid and has the necessary scopes configured."
- end
- end
-
# Exceptions classes that should bypass retry attempts. If your password didn't work the
# first time, it's not going to the third time.
NET_ERRORS = [:HTTPBadGateway, :HTTPBadRequest, :HTTPFailedDependency,
@@ -81,9 +70,9 @@ module Bundler
:HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity,
:HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze
FAIL_ERRORS = begin
- fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError, SecurityError]
+ fail_errors = [AuthenticationRequiredError, BadAuthenticationError, FallbackError]
fail_errors << Gem::Requirement::BadRequirementError
- fail_errors.concat(NET_ERRORS.map {|e| Gem::Net.const_get(e) })
+ fail_errors.concat(NET_ERRORS.map {|e| Net.const_get(e) })
end.freeze
class << self
@@ -95,7 +84,6 @@ module Bundler
self.max_retries = Bundler.settings[:retry] # How many retries for the API call
def initialize(remote)
- @cis = nil
@remote = remote
Socket.do_not_reverse_lookup = true
@@ -111,17 +99,15 @@ module Bundler
spec -= [nil, "ruby", ""]
spec_file_name = "#{spec.join "-"}.gemspec"
- uri = Gem::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz")
- spec = if uri.scheme == "file"
- path = Gem::Util.correct_for_windows_path(uri.path)
- Bundler.safe_load_marshal Bundler.rubygems.inflate(Gem.read_binary(path))
+ uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz")
+ if uri.scheme == "file"
+ path = Bundler.rubygems.correct_for_windows_path(uri.path)
+ Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(path))
elsif cached_spec_path = gemspec_cached_path(spec_file_name)
Bundler.load_gemspec(cached_spec_path)
else
- Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body)
+ Bundler.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."
@@ -138,11 +124,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
@@ -153,10 +148,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
@@ -182,7 +189,7 @@ module Bundler
agent << " ci/#{cis.join(",")}" if cis.any?
# add a random ID so we can consolidate runs server-side
- agent << " " << Gem::SecureRandom.hex(8)
+ agent << " " << SecureRandom.hex(8)
# add any user agent strings set in the config
extra_ua = Bundler.settings[:user_agent]
@@ -192,6 +199,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
@@ -201,49 +212,25 @@ module Bundler
"#<#{self.class}:0x#{object_id} uri=#{uri}>"
end
- def api_fetcher?
- fetchers.first.api_fetcher?
- end
-
- def gem_remote_fetcher
- @gem_remote_fetcher ||= begin
- require_relative "fetcher/gem_remote_fetcher"
- fetcher = GemRemoteFetcher.new Gem.configuration[:http_proxy]
- fetcher.headers["User-Agent"] = user_agent
- fetcher.headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri
- fetcher
- end
- 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, gem_remote_fetcher) }.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
- @cis ||= Bundler::CIDetector.ci_strings
+ env_cis = {
+ "TRAVIS" => "travis",
+ "CIRCLECI" => "circle",
+ "SEMAPHORE" => "semaphore",
+ "JENKINS_URL" => "jenkins",
+ "BUILDBOX" => "buildbox",
+ "GO_SERVER_URL" => "go",
+ "SNAP_CI" => "snap",
+ "GITLAB_CI" => "gitlab",
+ "GITHUB_ACTIONS" => "github",
+ "CI_NAME" => ENV["CI_NAME"],
+ "CI" => "ci",
+ }
+ env_cis.find_all {|env, _| ENV[env] }.map {|_, ci| ci }
end
def connection
@@ -253,9 +240,9 @@ module Bundler
Bundler.settings[:ssl_client_cert]
raise SSLError if needs_ssl && !defined?(OpenSSL::SSL)
- con = Gem::Net::HTTP::Persistent.new name: "bundler", proxy: :ENV
+ con = PersistentHTTP.new :name => "bundler", :proxy => :ENV
if gem_proxy = Gem.configuration[:http_proxy]
- con.proxy = Gem::URI.parse(gem_proxy) if gem_proxy != :no_proxy
+ con.proxy = Bundler::URI.parse(gem_proxy) if gem_proxy != :no_proxy
end
if remote_uri.scheme == "https"
@@ -288,10 +275,10 @@ module Bundler
end
HTTP_ERRORS = [
- Gem::Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH,
+ Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH,
Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
- Gem::Net::HTTPBadResponse, Gem::Net::HTTPHeaderSyntaxError, Gem::Net::ProtocolError,
- Gem::Net::HTTP::Persistent::Error, Zlib::BufError, Errno::EHOSTUNREACH
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
+ PersistentHTTP::Error, Zlib::BufError, Errno::EHOSTUNREACH
].freeze
def bundler_cert_store
@@ -307,7 +294,6 @@ module Bundler
end
else
store.set_default_paths
- require "rubygems/request"
Gem::Request.get_cert_files.each {|c| store.add_file c }
end
store
diff --git a/lib/bundler/fetcher/base.rb b/lib/bundler/fetcher/base.rb
index cfec2f8e94..62cc75add8 100644
--- a/lib/bundler/fetcher/base.rb
+++ b/lib/bundler/fetcher/base.rb
@@ -6,14 +6,12 @@ module Bundler
attr_reader :downloader
attr_reader :display_uri
attr_reader :remote
- attr_reader :gem_remote_fetcher
- def initialize(downloader, remote, display_uri, gem_remote_fetcher)
+ def initialize(downloader, remote, display_uri)
raise "Abstract class" if self.class == Base
@downloader = downloader
@remote = remote
@display_uri = display_uri
- @gem_remote_fetcher = gem_remote_fetcher
end
def remote_uri
@@ -40,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 6e5656d26a..77838f0361 100644
--- a/lib/bundler/fetcher/compact_index.rb
+++ b/lib/bundler/fetcher/compact_index.rb
@@ -4,6 +4,8 @@ require_relative "base"
require_relative "../worker"
module Bundler
+ autoload :CompactIndexClient, File.expand_path("../compact_index_client", __dir__)
+
class Fetcher
class CompactIndex < Base
def self.compact_index_request(method_name)
@@ -11,9 +13,9 @@ module Bundler
undef_method(method_name)
define_method(method_name) do |*args, &blk|
method.bind(self).call(*args, &blk)
- rescue NetworkDownError, CompactIndexClient::Updater::MismatchedChecksumError => e
+ rescue NetworkDownError, CompactIndexClient::Updater::MisMatchedChecksumError => e
raise HTTPError, e.message
- rescue AuthenticationRequiredError, BadAuthenticationError
+ rescue AuthenticationRequiredError
# Fail since we got a 401 from the server.
raise
rescue HTTPError => e
@@ -33,14 +35,21 @@ module Bundler
remaining_gems = gem_names.dup
until remaining_gems.empty?
- log_specs { "Looking up gems #{remaining_gems.inspect}" }
- deps = fetch_gem_infos(remaining_gems).flatten(1)
- next_gems = deps.flat_map {|d| d[CompactIndexClient::INFO_DEPS].flat_map(&:first) }.uniq
+ log_specs "Looking up gems #{remaining_gems.inspect}"
+
+ deps = begin
+ parallel_compact_index_client.dependencies(remaining_gems)
+ rescue TooManyRequestsError
+ @bundle_worker.stop if @bundle_worker
+ @bundle_worker = nil # reset it. Not sure if necessary
+ serial_compact_index_client.dependencies(remaining_gems)
+ end
+ 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
end
- @bundle_worker&.stop
+ @bundle_worker.stop if @bundle_worker
@bundle_worker = nil # reset it. Not sure if necessary
gem_info
@@ -51,9 +60,13 @@ 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.available?
- rescue CompactIndexClient::Updater::MismatchedChecksumError => e
+ compact_index_client.update_and_parse_checksums!
+ rescue CompactIndexClient::Updater::MisMatchedChecksumError => e
Bundler.ui.debug(e.message)
nil
end
@@ -72,20 +85,20 @@ module Bundler
end
end
- def fetch_gem_infos(names)
- in_parallel(names) {|name| compact_index_client.info(name) }
- rescue TooManyRequestsError # rubygems.org is rate limiting us, slow down.
- @bundle_worker&.stop
- @bundle_worker = nil # reset it. Not sure if necessary
- compact_index_client.reset!
- names.map {|name| compact_index_client.info(name) }
+ def parallel_compact_index_client
+ compact_index_client.execution_mode = lambda do |inputs, &blk|
+ func = lambda {|object, _index| blk.call(object) }
+ worker = bundle_worker(func)
+ inputs.each {|input| worker.enq(input) }
+ inputs.map { worker.deq }
+ end
+
+ compact_index_client
end
- def in_parallel(inputs, &blk)
- func = lambda {|object, _index| blk.call(object) }
- worker = bundle_worker(func)
- inputs.each {|input| worker.enq(input) }
- inputs.map { worker.deq }
+ def serial_compact_index_client
+ compact_index_client.sequential_execution_mode!
+ compact_index_client
end
def bundle_worker(func = nil)
@@ -112,7 +125,7 @@ module Bundler
rescue NetworkDownError => e
raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"]
ui.warn "Using the cached data for the new index because of a network error: #{e}"
- Gem::Net::HTTPNotModified.new(nil, nil, nil)
+ Net::HTTPNotModified.new(nil, nil, nil)
end
end
end
diff --git a/lib/bundler/fetcher/dependency.rb b/lib/bundler/fetcher/dependency.rb
index 0b807c9a4b..332f86139d 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?
@@ -34,10 +34,14 @@ module Bundler
returned_gems = spec_list.map(&:first).uniq
specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list)
- rescue MarshalError, HTTPError, GemspecError
+ rescue MarshalError
Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
Bundler.ui.debug "could not fetch from the dependency API, trying the full index"
nil
+ rescue HTTPError, GemspecError
+ Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
+ Bundler.ui.debug "could not fetch from the dependency API\nit's suggested to retry using the full index via `bundle install --full-index`"
+ nil
end
def dependency_specs(gem_names)
diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb
index 868b39b959..28d33f1aed 100644
--- a/lib/bundler/fetcher/downloader.rb
+++ b/lib/bundler/fetcher/downloader.rb
@@ -20,35 +20,31 @@ module Bundler
Bundler.ui.debug("HTTP #{response.code} #{response.message} #{filtered_uri}")
case response
- when Gem::Net::HTTPSuccess, Gem::Net::HTTPNotModified
+ when Net::HTTPSuccess, Net::HTTPNotModified
response
- when Gem::Net::HTTPRedirection
- new_uri = Gem::URI.parse(response["location"])
+ when Net::HTTPRedirection
+ new_uri = Bundler::URI.parse(response["location"])
if new_uri.host == uri.host
new_uri.user = uri.user
new_uri.password = uri.password
end
fetch(new_uri, headers, counter + 1)
- when Gem::Net::HTTPRequestedRangeNotSatisfiable
+ when Net::HTTPRequestedRangeNotSatisfiable
new_headers = headers.dup
new_headers.delete("Range")
new_headers["Accept-Encoding"] = "gzip"
fetch(uri, new_headers)
- when Gem::Net::HTTPRequestEntityTooLarge
+ when Net::HTTPRequestEntityTooLarge
raise FallbackError, response.body
- when Gem::Net::HTTPTooManyRequests
+ when Net::HTTPTooManyRequests
raise TooManyRequestsError, response.body
- when Gem::Net::HTTPUnauthorized
+ when Net::HTTPUnauthorized
raise BadAuthenticationError, uri.host if uri.userinfo
raise AuthenticationRequiredError, uri.host
- when Gem::Net::HTTPForbidden
- raise AuthenticationForbiddenError, uri.host
- when Gem::Net::HTTPNotFound
- raise FallbackError, "Gem::Net::HTTPNotFound: #{filtered_uri}"
+ when Net::HTTPNotFound
+ raise FallbackError, "Net::HTTPNotFound: #{filtered_uri}"
else
- message = "Gem::#{response.class.name.gsub(/\AGem::/, "")}"
- message += ": #{response.body}" unless response.body.empty?
- raise HTTPError, message
+ raise HTTPError, "#{response.class}#{": #{response.body}" unless response.body.empty?}"
end
end
@@ -58,7 +54,7 @@ module Bundler
filtered_uri = URICredentialsFilter.credential_filtered_uri(uri)
Bundler.ui.debug "HTTP GET #{filtered_uri}"
- req = Gem::Net::HTTP::Get.new uri.request_uri, headers
+ req = Net::HTTP::Get.new uri.request_uri, headers
if uri.user
user = CGI.unescape(uri.user)
password = uri.password ? CGI.unescape(uri.password) : nil
diff --git a/lib/bundler/fetcher/gem_remote_fetcher.rb b/lib/bundler/fetcher/gem_remote_fetcher.rb
deleted file mode 100644
index 3fc7b68263..0000000000
--- a/lib/bundler/fetcher/gem_remote_fetcher.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-require "rubygems/remote_fetcher"
-
-module Bundler
- class Fetcher
- class GemRemoteFetcher < Gem::RemoteFetcher
- def request(*args)
- super do |req|
- req.delete("User-Agent") if headers["User-Agent"]
- yield req if block_given?
- end
- end
- end
- end
-end
diff --git a/lib/bundler/fetcher/index.rb b/lib/bundler/fetcher/index.rb
index 6e37e1e5d1..6bb9fcc193 100644
--- a/lib/bundler/fetcher/index.rb
+++ b/lib/bundler/fetcher/index.rb
@@ -6,7 +6,7 @@ module Bundler
class Fetcher
class Index < Base
def specs(_gem_names)
- Bundler.rubygems.fetch_all_remote_specs(remote, gem_remote_fetcher)
+ Bundler.rubygems.fetch_all_remote_specs(remote)
rescue Gem::RemoteFetcher::FetchError => e
case e.message
when /certificate verify failed/
@@ -15,7 +15,8 @@ module Bundler
raise BadAuthenticationError, remote_uri if remote_uri.userinfo
raise AuthenticationRequiredError, remote_uri
when /403/
- raise AuthenticationForbiddenError, remote_uri
+ raise BadAuthenticationError, remote_uri if remote_uri.userinfo
+ raise AuthenticationRequiredError, remote_uri
else
raise HTTPError, "Could not fetch specs from #{display_uri} due to underlying error <#{e.message}>"
end
diff --git a/lib/bundler/force_platform.rb b/lib/bundler/force_platform.rb
index 7af33218cb..249a24ecd1 100644
--- a/lib/bundler/force_platform.rb
+++ b/lib/bundler/force_platform.rb
@@ -2,6 +2,8 @@
module Bundler
module ForcePlatform
+ private
+
# The `:force_ruby_platform` value used by dependencies for resolution, and
# by locked specifications for materialization is `false` by default, except
# for TruffleRuby. TruffleRuby generally needs to force the RUBY platform
diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb
index e61ed64450..71faeaf282 100644
--- a/lib/bundler/friendly_errors.rb
+++ b/lib/bundler/friendly_errors.rb
@@ -32,7 +32,7 @@ module Bundler
if Bundler.ui.debug?
Bundler.ui.trace error
else
- Bundler.ui.error error.message, wrap: true
+ Bundler.ui.error error.message, :wrap => true
end
when Thor::Error
Bundler.ui.error error.message
@@ -40,7 +40,7 @@ module Bundler
Bundler.ui.error "\nQuitting..."
Bundler.ui.trace error
when Gem::InvalidSpecificationException
- Bundler.ui.error error.message, wrap: true
+ Bundler.ui.error error.message, :wrap => true
when SystemExit
when *[defined?(Java::JavaLang::OutOfMemoryError) && Java::JavaLang::OutOfMemoryError].compact
Bundler.ui.error "\nYour JVM has run out of memory, and Bundler cannot continue. " \
@@ -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,9 +93,9 @@ module Bundler
end
def serialized_exception_for(e)
- <<~EOS
+ <<-EOS.gsub(/^ {8}/, "")
#{e.class}: #{e.message}
- #{e.backtrace&.join("\n ")&.chomp}
+ #{e.backtrace && e.backtrace.join("\n ").chomp}
EOS
end
diff --git a/lib/bundler/gem_helper.rb b/lib/bundler/gem_helper.rb
index 5ce0ef6280..0bbd2d9b75 100644
--- a/lib/bundler/gem_helper.rb
+++ b/lib/bundler/gem_helper.rb
@@ -21,7 +21,7 @@ module Bundler
def gemspec(&block)
gemspec = instance.gemspec
- block&.call(gemspec)
+ block.call(gemspec) if block
gemspec
end
end
@@ -47,7 +47,7 @@ module Bundler
built_gem_path = build_gem
end
- desc "Generate SHA512 checksum of #{name}-#{version}.gem into the checksums directory."
+ desc "Generate SHA512 checksum if #{name}-#{version}.gem into the checksums directory."
task "build:checksum" => "build" do
build_checksum(built_gem_path)
end
@@ -152,7 +152,8 @@ module Bundler
def gem_push_host
env_rubygems_host = ENV["RUBYGEMS_HOST"]
- env_rubygems_host = nil if env_rubygems_host&.empty?
+ env_rubygems_host = nil if
+ env_rubygems_host && env_rubygems_host.empty?
allowed_push_host || env_rubygems_host || "rubygems.org"
end
@@ -215,9 +216,9 @@ module Bundler
def sh_with_status(cmd, &block)
Bundler.ui.debug(cmd)
SharedHelpers.chdir(base) do
- outbuf = IO.popen(cmd, err: [:child, :out], &:read)
+ outbuf = IO.popen(cmd, :err => [:child, :out], &:read)
status = $?
- block&.call(outbuf) if status.success?
+ block.call(outbuf) if status.success? && block
[outbuf, status]
end
end
diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb
index 70ccceb491..2e6d788f9c 100644
--- a/lib/bundler/gem_helpers.rb
+++ b/lib/bundler/gem_helpers.rb
@@ -34,11 +34,6 @@ module Bundler
end
module_function :local_platform
- def generic_local_platform_is_ruby?
- generic_local_platform == Gem::Platform::RUBY
- end
- module_function :generic_local_platform_is_ruby?
-
def platform_specificity_match(spec_platform, user_platform)
spec_platform = Gem::Platform.new(spec_platform)
@@ -46,27 +41,13 @@ module Bundler
end
module_function :platform_specificity_match
- def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
- matching = if force_ruby
- specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
- else
- specs.select {|spec| spec.match_platform(platform) }
- end
-
- if prefer_locked
- locked_originally = matching.select {|spec| spec.is_a?(LazySpecification) }
- return locked_originally if locked_originally.any?
- end
+ def select_best_platform_match(specs, platform)
+ matching = specs.select {|spec| spec.match_platform(platform) }
sort_best_platform_match(matching, platform)
end
module_function :select_best_platform_match
- def select_best_local_platform_match(specs, force_ruby: false)
- select_best_platform_match(specs, local_platform, force_ruby: force_ruby).map(&:materialize_for_installation).compact
- end
- module_function :select_best_local_platform_match
-
def sort_best_platform_match(matching, platform)
exact = matching.select {|spec| spec.platform == platform }
return exact if exact.any?
@@ -126,6 +107,8 @@ module Bundler
def same_deps(spec, exemplary_spec)
same_runtime_deps = spec.dependencies.sort == exemplary_spec.dependencies.sort
+ return same_runtime_deps unless spec.is_a?(Gem::Specification) && exemplary_spec.is_a?(Gem::Specification)
+
same_metadata_deps = spec.required_ruby_version == exemplary_spec.required_ruby_version && spec.required_rubygems_version == exemplary_spec.required_rubygems_version
same_runtime_deps && same_metadata_deps
end
diff --git a/lib/bundler/gem_version_promoter.rb b/lib/bundler/gem_version_promoter.rb
index ecc65b4956..f08fceb7e2 100644
--- a/lib/bundler/gem_version_promoter.rb
+++ b/lib/bundler/gem_version_promoter.rb
@@ -45,37 +45,17 @@ module Bundler
# Given a Resolver::Package and an Array of Specifications of available
# versions for a gem, this method will return the Array of Specifications
- # sorted in an order to give preference to the current level (:major, :minor
- # or :patch) when resolution is deciding what versions best resolve all
- # dependencies in the bundle.
+ # sorted (and possibly truncated if strict is true) in an order to give
+ # preference to the current level (:major, :minor or :patch) when resolution
+ # is deciding what versions best resolve all dependencies in the bundle.
# @param package [Resolver::Package] The package being resolved.
# @param specs [Specification] An array of Specifications for the package.
- # @return [Specification] A new instance of the Specification Array sorted.
+ # @return [Specification] A new instance of the Specification Array sorted and
+ # possibly filtered.
def sort_versions(package, specs)
- locked_version = package.locked_version
-
- result = specs.sort do |a, b|
- unless package.prerelease_specified? || pre?
- a_pre = a.prerelease?
- b_pre = b.prerelease?
-
- next 1 if a_pre && !b_pre
- next -1 if b_pre && !a_pre
- end
+ specs = filter_dep_specs(specs, package) if strict
- if major? || locked_version.nil?
- b <=> a
- elsif either_version_older_than_locked?(a, b, locked_version)
- b <=> a
- elsif segments_do_not_match?(a, b, :major)
- a <=> b
- elsif !minor? && segments_do_not_match?(a, b, :minor)
- a <=> b
- else
- b <=> a
- end
- end
- post_sort(result, package.unlock?, locked_version)
+ sort_dep_specs(specs, package)
end
# @return [bool] Convenience method for testing value of level variable.
@@ -93,18 +73,9 @@ module Bundler
pre == true
end
- # Given a Resolver::Package and an Array of Specifications of available
- # versions for a gem, this method will truncate the Array if strict
- # is true. That means filtering out downgrades from the version currently
- # locked, and filtering out upgrades that go past the selected level (major,
- # minor, or patch).
- # @param package [Resolver::Package] The package being resolved.
- # @param specs [Specification] An array of Specifications for the package.
- # @return [Specification] A new instance of the Specification Array
- # truncated.
- def filter_versions(package, specs)
- return specs unless strict
+ private
+ def filter_dep_specs(specs, package)
locked_version = package.locked_version
return specs if locked_version.nil? || major?
@@ -118,10 +89,35 @@ module Bundler
end
end
- private
+ def sort_dep_specs(specs, package)
+ locked_version = package.locked_version
+
+ result = specs.sort do |a, b|
+ unless locked_version && (package.prerelease_specified? || pre?)
+ a_pre = a.prerelease?
+ b_pre = b.prerelease?
+
+ next -1 if a_pre && !b_pre
+ next 1 if b_pre && !a_pre
+ end
+
+ if major?
+ a <=> b
+ elsif either_version_older_than_locked?(a, b, locked_version)
+ a <=> b
+ elsif segments_do_not_match?(a, b, :major)
+ b <=> a
+ elsif !minor? && segments_do_not_match?(a, b, :minor)
+ b <=> a
+ else
+ a <=> b
+ end
+ end
+ post_sort(result, package.unlock?, locked_version)
+ 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)
@@ -137,13 +133,13 @@ module Bundler
if unlock || locked_version.nil?
result
else
- move_version_to_beginning(result, locked_version)
+ move_version_to_end(result, locked_version)
end
end
- def move_version_to_beginning(result, version)
+ def move_version_to_end(result, version)
move, keep = result.partition {|s| s.version.to_s == version.to_s }
- move.concat(keep)
+ keep.concat(move)
end
end
end
diff --git a/lib/bundler/graph.rb b/lib/bundler/graph.rb
index b22b17a453..3c008e63e3 100644
--- a/lib/bundler/graph.rb
+++ b/lib/bundler/graph.rb
@@ -84,7 +84,7 @@ module Bundler
else
raise ArgumentError, "2nd argument is invalid"
end
- label.nil? ? {} : { label: label }
+ label.nil? ? {} : { :label => label }
end
def spec_for_dependency(dependency)
@@ -103,7 +103,7 @@ module Bundler
end
def g
- @g ||= ::GraphViz.digraph(@graph_name, concentrate: true, normalize: true, nodesep: 0.55) do |g|
+ @g ||= ::GraphViz.digraph(@graph_name, :concentrate => true, :normalize => true, :nodesep => 0.55) do |g|
g.edge[:weight] = 2
g.edge[:fontname] = g.node[:fontname] = "Arial, Helvetica, SansSerif"
g.edge[:fontsize] = 12
@@ -114,10 +114,10 @@ module Bundler
@groups.each do |group|
g.add_nodes(
group, {
- style: "filled",
- fillcolor: "#B9B9D5",
- shape: "box3d",
- fontsize: 16,
+ :style => "filled",
+ :fillcolor => "#B9B9D5",
+ :shape => "box3d",
+ :fontsize => 16,
}.merge(@node_options[group])
)
end
@@ -125,8 +125,8 @@ module Bundler
@relations.each do |parent, children|
children.each do |child|
if @groups.include?(parent)
- g.add_nodes(child, { style: "filled", fillcolor: "#B9B9D5" }.merge(@node_options[child]))
- g.add_edges(parent, child, { constraint: false }.merge(@edge_options["#{parent}_#{child}"]))
+ g.add_nodes(child, { :style => "filled", :fillcolor => "#B9B9D5" }.merge(@node_options[child]))
+ g.add_edges(parent, child, { :constraint => false }.merge(@edge_options["#{parent}_#{child}"]))
else
g.add_nodes(child, @node_options[child])
g.add_edges(parent, child, @edge_options["#{parent}_#{child}"])
@@ -135,7 +135,7 @@ module Bundler
end
if @output_format.to_s == "debug"
- $stdout.puts g.output none: String
+ $stdout.puts g.output :none => String
Bundler.ui.info "debugging bundle viz..."
else
begin
diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb
index df46facc88..0301986ca9 100644
--- a/lib/bundler/index.rb
+++ b/lib/bundler/index.rb
@@ -10,30 +10,30 @@ 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"
+ RUBY = "ruby".freeze
+ NULL = "\0".freeze
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 c7e93c9ee0..c2edc9b43a 100644
--- a/lib/bundler/injector.rb
+++ b/lib/bundler/injector.rb
@@ -2,7 +2,7 @@
module Bundler
class Injector
- INJECTED_GEMS = "injected gems"
+ INJECTED_GEMS = "injected gems".freeze
def self.inject(new_deps, options = {})
injector = new(new_deps, options)
@@ -23,10 +23,13 @@ module Bundler
# @param [Pathname] lockfile_path The lockfile in which to inject the new dependency.
# @return [Array]
def inject(gemfile_path, lockfile_path)
- Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true)
+ if Bundler.frozen_bundle?
+ # ensure the lock and Gemfile are synced
+ Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true)
+ end
# temporarily unfreeze
- Bundler.settings.temporary(deployment: false, frozen: false) do
+ Bundler.settings.temporary(:deployment => false, :frozen => false) do
# evaluate the Gemfile we have now
builder = Dsl.new
builder.eval_gemfile(gemfile_path)
@@ -47,7 +50,7 @@ module Bundler
append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any?
# since we resolved successfully, write out the lockfile
- @definition.lock
+ @definition.lock(Bundler.default_lockfile)
# invalidate the cached Bundler.definition
Bundler.reset_paths!
@@ -83,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
@@ -117,10 +120,9 @@ module Bundler
github = ", :github => \"#{d.github}\"" unless d.github.nil?
branch = ", :branch => \"#{d.branch}\"" unless d.branch.nil?
ref = ", :ref => \"#{d.ref}\"" unless d.ref.nil?
- glob = ", :glob => \"#{d.glob}\"" unless d.glob.nil?
require_path = ", :require => #{convert_autorequire(d.autorequire)}" unless d.autorequire.nil?
- %(gem #{name}#{requirement}#{group}#{source}#{path}#{git}#{github}#{branch}#{ref}#{glob}#{require_path})
+ %(gem #{name}#{requirement}#{group}#{source}#{path}#{git}#{github}#{branch}#{ref}#{require_path})
end.join("\n")
end
diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb
index ca17d0233e..5c184f67a1 100644
--- a/lib/bundler/inline.rb
+++ b/lib/bundler/inline.rb
@@ -39,56 +39,35 @@ def gemfile(install = false, options = {}, &gemfile)
Bundler.ui = ui
raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty?
- old_gemfile = ENV["BUNDLE_GEMFILE"]
-
- Bundler.unbundle_env!
-
- begin
+ Bundler.with_unbundled_env do
Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir))
Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins?
builder = Bundler::Dsl.new
builder.instance_eval(&gemfile)
+ builder.check_primary_source_safety
- Bundler.settings.temporary(deployment: false, frozen: false) do
+ Bundler.settings.temporary(:deployment => false, :frozen => false) do
definition = builder.to_definition(nil, true)
+ def definition.lock(*); end
definition.validate_runtime!
if install || definition.missing_specs?
- Bundler.settings.temporary(inline: true, no_install: false) do
- installer = Bundler::Installer.install(Bundler.root, definition, system: true)
+ Bundler.settings.temporary(:inline => true, :no_install => false) do
+ installer = Bundler::Installer.install(Bundler.root, definition, :system => true)
installer.post_install_messages.each do |name, message|
Bundler.ui.info "Post-install message from #{name}:\n#{message}"
end
end
end
- begin
- runtime = Bundler::Runtime.new(nil, definition).setup
- rescue Gem::LoadError => e
- name = e.name
- version = e.requirement.requirements.first[1]
- activated_version = Gem.loaded_specs[name].version
-
- Bundler.ui.info \
- "The #{name} gem was resolved to #{version}, but #{activated_version} was activated by Bundler while installing it, causing a conflict. " \
- "Bundler will now retry resolving with #{activated_version} instead."
-
- builder.dependencies.delete_if {|d| d.name == name }
- builder.instance_eval { gem name, activated_version }
- definition = builder.to_definition(nil, true)
-
- retry
- end
-
- runtime.require
- end
- ensure
- if old_gemfile
- ENV["BUNDLE_GEMFILE"] = old_gemfile
- else
- ENV["BUNDLE_GEMFILE"] = ""
+ runtime = Bundler::Runtime.new(nil, definition)
+ runtime.setup.require
end
end
+
+ if ENV["BUNDLE_GEMFILE"].nil?
+ ENV["BUNDLE_GEMFILE"] = ""
+ end
end
diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb
index 0d7f26f9b7..680e812ac8 100644
--- a/lib/bundler/installer.rb
+++ b/lib/bundler/installer.rb
@@ -69,7 +69,9 @@ module Bundler
Bundler.create_bundle_path
ProcessLock.lock do
- @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
+ if Bundler.frozen_bundle?
+ @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
+ end
if @definition.dependencies.empty?
Bundler.ui.warn "The Gemfile specifies no dependencies"
@@ -88,7 +90,7 @@ module Bundler
Gem::Specification.reset # invalidate gem specification cache so that installed gems are immediately available
- lock
+ lock unless Bundler.frozen_bundle?
Standalone.new(options[:standalone], @definition).generate if options[:standalone]
end
end
@@ -134,12 +136,12 @@ module Bundler
mode = Gem.win_platform? ? "wb:UTF-8" : "w"
require "erb"
- content = ERB.new(template, trim_mode: "-").result(binding)
+ content = ERB.new(template, :trim_mode => "-").result(binding)
- File.write(binstub_path, content, mode: mode, perm: 0o777 & ~File.umask)
+ File.write(binstub_path, content, :mode => mode, :perm => 0o777 & ~File.umask)
if Gem.win_platform? || options[:all_platforms]
prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n"
- File.write("#{binstub_path}.cmd", prefix + content, mode: mode)
+ File.write("#{binstub_path}.cmd", prefix + content, :mode => mode)
end
end
@@ -177,12 +179,12 @@ module Bundler
mode = Gem.win_platform? ? "wb:UTF-8" : "w"
require "erb"
- content = ERB.new(template, trim_mode: "-").result(binding)
+ content = ERB.new(template, :trim_mode => "-").result(binding)
- File.write("#{bin_path}/#{executable}", content, mode: mode, perm: 0o755)
+ File.write("#{bin_path}/#{executable}", content, :mode => mode, :perm => 0o755)
if Gem.win_platform? || options[:all_platforms]
prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n"
- File.write("#{bin_path}/#{executable}.cmd", prefix + content, mode: mode)
+ File.write("#{bin_path}/#{executable}.cmd", prefix + content, :mode => mode)
end
end
end
@@ -194,14 +196,9 @@ module Bundler
# that said, it's a rare situation (other than rake), and parallel
# installation is SO MUCH FASTER. so we let people opt in.
def install(options)
- standalone = options[:standalone]
- force = options[:force]
- local = options[:local]
+ force = options["force"]
jobs = installation_parallelization(options)
- spec_installations = ParallelInstaller.call(self, @definition.specs, jobs, standalone, force, local: local)
- spec_installations.each do |installation|
- post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message?
- end
+ install_in_parallel jobs, options[:standalone], force
end
def installation_parallelization(options)
@@ -217,17 +214,17 @@ module Bundler
end
def load_plugins
- Gem.load_plugins
+ Bundler.rubygems.load_plugins
requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) }
path_plugin_files = requested_path_gems.map do |spec|
- spec.matches_for_glob("rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
+ Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
rescue TypeError
error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
raise Gem::InvalidSpecificationException, error_message
end.flatten
- Gem.load_plugin_files(path_plugin_files)
- Gem.load_env_plugins
+ Bundler.rubygems.load_plugin_files(path_plugin_files)
+ Bundler.rubygems.load_env_plugins
end
def ensure_specs_are_compatible!
@@ -243,21 +240,28 @@ module Bundler
end
end
+ def install_in_parallel(size, standalone, force = false)
+ spec_installations = ParallelInstaller.call(self, @definition.specs, size, standalone, force)
+ spec_installations.each do |installation|
+ post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message?
+ end
+ end
+
# returns whether or not a re-resolve was needed
def resolve_if_needed(options)
- @definition.prefer_local! if options[:"prefer-local"]
-
- if options[:local] || (@definition.no_resolve_needed? && !@definition.missing_specs?)
- @definition.resolve_with_cache!
- false
- else
- @definition.resolve_remotely!
- true
+ @definition.resolution_mode = options
+
+ if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file?
+ return false if @definition.nothing_changed? && !@definition.missing_specs?
end
+
+ @definition.setup_sources_for_resolve
+
+ true
end
- def lock
- @definition.lock
+ def lock(opts = {})
+ @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections])
end
end
end
diff --git a/lib/bundler/installer/gem_installer.rb b/lib/bundler/installer/gem_installer.rb
index 1da91857bd..9a013eea4d 100644
--- a/lib/bundler/installer/gem_installer.rb
+++ b/lib/bundler/installer/gem_installer.rb
@@ -2,28 +2,27 @@
module Bundler
class GemInstaller
- attr_reader :spec, :standalone, :worker, :force, :local, :installer
+ attr_reader :spec, :standalone, :worker, :force, :installer
- def initialize(spec, installer, standalone = false, worker = 0, force = false, local = false)
+ def initialize(spec, installer, standalone = false, worker = 0, force = false)
@spec = spec
@installer = installer
@standalone = standalone
@worker = worker
@force = force
- @local = local
end
def install_from_spec
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
@@ -54,10 +53,10 @@ module Bundler
def install
spec.source.install(
spec,
- force: force,
- local: local,
- build_args: Array(spec_settings),
- previous_spec: previous_spec,
+ :force => force,
+ :ensure_builtin_gems_cached => standalone,
+ :build_args => Array(spec_settings),
+ :previous_spec => previous_spec,
)
end
@@ -78,7 +77,7 @@ module Bundler
if Bundler.settings[:bin] && standalone
installer.generate_standalone_bundler_executable_stubs(spec)
elsif Bundler.settings[:bin]
- installer.generate_bundler_executable_stubs(spec, force: true)
+ installer.generate_bundler_executable_stubs(spec, :force => true)
end
end
end
diff --git a/lib/bundler/installer/parallel_installer.rb b/lib/bundler/installer/parallel_installer.rb
index d10e5ec924..dce7133769 100644
--- a/lib/bundler/installer/parallel_installer.rb
+++ b/lib/bundler/installer/parallel_installer.rb
@@ -42,7 +42,8 @@ module Bundler
# Checks installed dependencies against spec's dependencies to make
# sure needed dependencies have been installed.
- def dependencies_installed?(installed_specs)
+ def dependencies_installed?(all_specs)
+ installed_specs = all_specs.select(&:installed?).map(&:name)
dependencies.all? {|d| installed_specs.include? d.name }
end
@@ -62,24 +63,20 @@ module Bundler
end
end
- def self.call(*args, **kwargs)
- new(*args, **kwargs).call
+ def self.call(*args)
+ new(*args).call
end
attr_reader :size
- def initialize(installer, all_specs, size, standalone, force, local: false, skip: nil)
+ def initialize(installer, all_specs, size, standalone, force)
@installer = installer
@size = size
@standalone = standalone
@force = force
- @local = local
@specs = all_specs.map {|s| SpecInstallation.new(s) }
- @specs.each do |spec_install|
- spec_install.state = :installed if skip.include?(spec_install.name)
- end if skip
@spec_set = all_specs
- @rake = @specs.find {|s| s.name == "rake" unless s.installed? }
+ @rake = @specs.find {|s| s.name == "rake" }
end
def call
@@ -94,10 +91,35 @@ module Bundler
install_serially
end
+ check_for_unmet_dependencies
+
handle_error if failed_specs.any?
@specs
ensure
- worker_pool&.stop
+ worker_pool && 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 trying to 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|
+ warning << "* #{unmet_spec_dependency}, depended upon #{spec.full_name}, unsatisfied by #{@specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) }.full_name}"
+ end
+ end
+
+ Bundler.ui.warn(warning.join("\n"))
end
private
@@ -128,7 +150,7 @@ module Bundler
def do_install(spec_install, worker_num)
Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install)
gem_installer = Bundler::GemInstaller.new(
- spec_install.spec, @installer, @standalone, worker_num, @force, @local
+ spec_install.spec, @installer, @standalone, worker_num, @force
)
success, message = gem_installer.install_from_spec
if success
@@ -186,14 +208,8 @@ module Bundler
# previously installed specifications. We continue until all specs
# are installed.
def enqueue_specs
- installed_specs = {}
- @specs.each do |spec|
- next unless spec.installed?
- installed_specs[spec.name] = true
- end
-
- @specs.each do |spec|
- if spec.ready_to_enqueue? && spec.dependencies_installed?(installed_specs)
+ @specs.select(&:ready_to_enqueue?).each do |spec|
+ if spec.dependencies_installed? @specs
spec.state = :enqueued
worker_pool.enq spec
end
diff --git a/lib/bundler/installer/standalone.rb b/lib/bundler/installer/standalone.rb
index cf5993448c..2efef61648 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|
@@ -53,24 +52,14 @@ module Bundler
def gem_path(path, spec)
full_path = Pathname.new(path).absolute? ? path : File.join(spec.full_gem_path, path)
- if spec.source.instance_of?(Source::Path) && spec.source.path.absolute?
+ if spec.source.instance_of?(Source::Path)
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
- end
-
- def prevent_gem_activation
- <<~'END'
- module Kernel
- remove_method(:gem) if private_method_defined?(:gem)
-
- def gem(*)
- end
-
- private :gem
- end
- END
+ rescue TypeError
+ error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
+ raise Gem::InvalidSpecificationException.new(error_message)
end
def define_path_helpers
@@ -98,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 8669e021c2..6749892930 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -4,60 +4,39 @@ require_relative "force_platform"
module Bundler
class LazySpecification
- include MatchMetadata
include MatchPlatform
include ForcePlatform
- attr_reader :name, :version, :platform
- attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version
-
- alias_method :runtime_dependencies, :dependencies
-
- def self.from_spec(s)
- lazy_spec = new(s.name, s.version, s.platform, s.source)
- lazy_spec.dependencies = s.dependencies
- lazy_spec.required_ruby_version = s.required_ruby_version
- lazy_spec.required_rubygems_version = s.required_rubygems_version
- lazy_spec
- end
+ attr_reader :name, :version, :dependencies, :platform
+ attr_accessor :source, :remote, :force_ruby_platform
def initialize(name, version, platform, source = nil)
@name = name
@version = version
@dependencies = []
- @required_ruby_version = Gem::Requirement.default
- @required_rubygems_version = Gem::Requirement.default
@platform = platform || Gem::Platform::RUBY
@source = source
@force_ruby_platform = default_force_ruby_platform
end
def full_name
- @full_name ||= if platform == Gem::Platform::RUBY
+ if platform == Gem::Platform::RUBY
"#{@name}-#{@version}"
else
"#{@name}-#{@version}-#{platform}"
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
+ identifier == other.identifier
end
def eql?(other)
- full_name.eql?(other.full_name)
+ identifier.eql?(other.identifier)
end
def hash
- full_name.hash
+ identifier.hash
end
##
@@ -82,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
@@ -105,7 +89,7 @@ module Bundler
installable_candidates = GemHelpers.select_best_platform_match(matching_specs, target_platform)
- specification = __materialize__(installable_candidates, fallback_to_non_installable: false)
+ specification = __materialize__(installable_candidates, :fallback_to_non_installable => false)
return specification unless specification.nil?
if target_platform != platform
@@ -125,7 +109,9 @@ module Bundler
# bad gem.
def __materialize__(candidates, fallback_to_non_installable: Bundler.frozen_bundle?)
search = candidates.reverse.find do |spec|
- spec.is_a?(StubSpecification) || spec.matches_current_metadata?
+ spec.is_a?(StubSpecification) ||
+ (spec.matches_current_ruby? &&
+ spec.matches_current_rubygems?)
end
if search.nil? && fallback_to_non_installable
search = candidates.last
@@ -136,7 +122,15 @@ module Bundler
end
def to_s
- lock_name
+ @__to_s ||= if platform == Gem::Platform::RUBY
+ "#{name} (#{version})"
+ else
+ "#{name} (#{version}-#{platform})"
+ end
+ end
+
+ def identifier
+ @__identifier ||= [name, version, platform.to_s]
end
def git_version
@@ -144,10 +138,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 a646d00ee1..23413dbdd6 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
@@ -46,7 +45,7 @@ module Bundler
# gems with the same name, but different platform
# are ordered consistently
specs.sort_by(&:full_name).each do |spec|
- next if spec.name == "bundler"
+ next if spec.name == "bundler".freeze
out << spec.to_lock
end
end
@@ -66,21 +65,13 @@ module Bundler
end
end
- def add_checksums
- return unless definition.locked_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)
end
def add_bundled_with
- add_section("BUNDLED WITH", definition.bundler_version_to_lock.to_s)
+ add_section("BUNDLED WITH", Bundler::VERSION)
end
def add_section(name, value)
diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb
index 8a15e356c4..0ec5b7de8a 100644
--- a/lib/bundler/lockfile_parser.rb
+++ b/lib/bundler/lockfile_parser.rb
@@ -2,49 +2,18 @@
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,
- )
-
- BUNDLED = "BUNDLED WITH"
- DEPENDENCIES = "DEPENDENCIES"
- CHECKSUMS = "CHECKSUMS"
- PLATFORMS = "PLATFORMS"
- RUBY = "RUBY VERSION"
- GIT = "GIT"
- GEM = "GEM"
- PATH = "PATH"
- PLUGIN = "PLUGIN SOURCE"
- SPECS = " specs:"
- OPTIONS = /^ ([a-z]+): (.*)$/i
+ attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version
+
+ BUNDLED = "BUNDLED WITH".freeze
+ DEPENDENCIES = "DEPENDENCIES".freeze
+ PLATFORMS = "PLATFORMS".freeze
+ RUBY = "RUBY VERSION".freeze
+ GIT = "GIT".freeze
+ GEM = "GEM".freeze
+ PATH = "PATH".freeze
+ PLUGIN = "PLUGIN SOURCE".freeze
+ SPECS = " specs:".freeze
+ OPTIONS = /^ ([a-z]+): (.*)$/i.freeze
SOURCE = [GIT, GEM, PATH, PLUGIN].freeze
SECTIONS_BY_VERSION_INTRODUCED = {
@@ -52,18 +21,14 @@ 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)
@@ -72,7 +37,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
@@ -95,53 +60,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
- # This is a temporary solution to make this feature disabled by default
- # for all gemfiles that don't already explicitly include the feature.
- @checksums = true
- @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(&:identifier)
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?
@@ -160,9 +109,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"
@@ -192,19 +153,18 @@ module Bundler
(?:#{space}\(([^-]*) # Space, followed by version
(?:-(.*))?\))? # Optional platform
(!)? # Optional pinned marker
- (?:#{space}([^ ]+))? # Optional checksum
$ # Line end
- /xo
+ /xo.freeze
def parse_dependency(line)
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)
@@ -225,65 +185,40 @@ 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
- 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, @current_source)
+ @current_spec = LazySpecification.new(name, version, platform)
+ @current_spec.source = @current_source
@current_source.add_dependency_names(name)
- @specs[@current_spec.full_name] = @current_spec
+ @specs[@current_spec.identifier] = @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
end
def parse_platform(line)
- @platforms << Gem::Platform.new($1.strip) if line =~ /^ (.*)$/
+ @platforms << Gem::Platform.new($1) if line =~ /^ (.*)$/
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 dae05bd945..805bd5450d 100644
--- a/lib/bundler/man/bundle-add.1
+++ b/lib/bundler/man/bundle-add.1
@@ -1,70 +1,82 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-ADD" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-ADD" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install
+.
.SH "SYNOPSIS"
-\fBbundle add\fR \fIGEM_NAME\fR [\-\-group=GROUP] [\-\-version=VERSION] [\-\-source=SOURCE] [\-\-path=PATH] [\-\-git=GIT|\-\-github=GITHUB] [\-\-branch=BRANCH] [\-\-ref=REF] [\-\-skip\-install] [\-\-strict|\-\-optimistic]
+\fBbundle add\fR \fIGEM_NAME\fR [\-\-group=GROUP] [\-\-version=VERSION] [\-\-source=SOURCE] [\-\-path=PATH] [\-\-git=GIT] [\-\-github=GITHUB] [\-\-branch=BRANCH] [\-\-ref=REF] [\-\-skip\-install] [\-\-strict] [\-\-optimistic]
+.
.SH "DESCRIPTION"
-Adds the named gem to the [\fBGemfile(5)\fR][Gemfile(5)] and run \fBbundle install\fR\. \fBbundle install\fR can be avoided by using the flag \fB\-\-skip\-install\fR\.
+Adds the named gem to the Gemfile and run \fBbundle install\fR\. \fBbundle install\fR can be avoided by using the flag \fB\-\-skip\-install\fR\.
+.
+.P
+Example:
+.
+.P
+bundle add rails
+.
+.P
+bundle add rails \-\-version "< 3\.0, > 1\.1"
+.
+.P
+bundle add rails \-\-version "~> 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development"
+.
+.P
+bundle add rails \-\-skip\-install
+.
+.P
+bundle add rails \-\-group "development, test"
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-version\fR, \fB\-v\fR
Specify version requirements(s) for the added gem\.
+.
.TP
\fB\-\-group\fR, \fB\-g\fR
Specify the group(s) for the added gem\. Multiple groups should be separated by commas\.
+.
.TP
\fB\-\-source\fR, \fB\-s\fR
Specify the source for the added gem\.
+.
.TP
\fB\-\-require\fR, \fB\-r\fR
Adds require path to gem\. Provide false, or a path as a string\.
+.
.TP
\fB\-\-path\fR
Specify the file system path for the added gem\.
+.
.TP
\fB\-\-git\fR
Specify the git source for the added gem\.
+.
.TP
\fB\-\-github\fR
Specify the github source for the added gem\.
+.
.TP
\fB\-\-branch\fR
Specify the git branch for the added gem\.
+.
.TP
\fB\-\-ref\fR
Specify the git ref for the added gem\.
+.
.TP
\fB\-\-skip\-install\fR
Adds the gem to the Gemfile but does not install it\.
+.
.TP
\fB\-\-optimistic\fR
Adds optimistic declaration of version\.
+.
.TP
\fB\-\-strict\fR
Adds strict declaration of version\.
-.SH "EXAMPLES"
-.IP "1." 4
-You can add the \fBrails\fR gem to the Gemfile without any version restriction\. The source of the gem will be the global source\.
-.IP
-\fBbundle add rails\fR
-.IP "2." 4
-You can add the \fBrails\fR gem with version greater than 1\.1 (not including 1\.1) and less than 3\.0\.
-.IP
-\fBbundle add rails \-\-version "> 1\.1, < 3\.0"\fR
-.IP "3." 4
-You can use the \fBhttps://gems\.example\.com\fR custom source and assign the gem to a group\.
-.IP
-\fBbundle add rails \-\-version "~> 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development"\fR
-.IP "4." 4
-The following adds the \fBgem\fR entry to the Gemfile without installing the gem\. You can install gems later via \fBbundle install\fR\.
-.IP
-\fBbundle add rails \-\-skip\-install\fR
-.IP "5." 4
-You can assign the gem to more than one group\.
-.IP
-\fBbundle add rails \-\-group "development, test"\fR
-.IP "" 0
-.SH "SEE ALSO"
-Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR, bundle\-remove(1) \fIbundle\-remove\.1\.html\fR
+
diff --git a/lib/bundler/man/bundle-add.1.ronn b/lib/bundler/man/bundle-add.1.ronn
index 8b38c7a248..37c92e5fcd 100644
--- a/lib/bundler/man/bundle-add.1.ronn
+++ b/lib/bundler/man/bundle-add.1.ronn
@@ -1,19 +1,26 @@
bundle-add(1) -- Add gem to the Gemfile and run bundle install
-==============================================================
+================================================================
## SYNOPSIS
-`bundle add` <GEM_NAME> [--group=GROUP] [--version=VERSION] [--source=SOURCE]
- [--path=PATH] [--git=GIT|--github=GITHUB] [--branch=BRANCH] [--ref=REF]
- [--skip-install] [--strict|--optimistic]
+`bundle add` <GEM_NAME> [--group=GROUP] [--version=VERSION] [--source=SOURCE] [--path=PATH] [--git=GIT] [--github=GITHUB] [--branch=BRANCH] [--ref=REF] [--skip-install] [--strict] [--optimistic]
## DESCRIPTION
+Adds the named gem to the Gemfile and run `bundle install`. `bundle install` can be avoided by using the flag `--skip-install`.
-Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
-`bundle install` can be avoided by using the flag `--skip-install`.
+Example:
-## OPTIONS
+bundle add rails
+
+bundle add rails --version "< 3.0, > 1.1"
+
+bundle add rails --version "~> 5.0.0" --source "https://gems.example.com" --group "development"
+
+bundle add rails --skip-install
+
+bundle add rails --group "development, test"
+## OPTIONS
* `--version`, `-v`:
Specify version requirements(s) for the added gem.
@@ -49,33 +56,3 @@ Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
* `--strict`:
Adds strict declaration of version.
-
-## EXAMPLES
-
-1. You can add the `rails` gem to the Gemfile without any version restriction.
- The source of the gem will be the global source.
-
- `bundle add rails`
-
-2. You can add the `rails` gem with version greater than 1.1 (not including 1.1) and less than 3.0.
-
- `bundle add rails --version "> 1.1, < 3.0"`
-
-3. You can use the `https://gems.example.com` custom source and assign the gem
- to a group.
-
- `bundle add rails --version "~> 5.0.0" --source "https://gems.example.com" --group "development"`
-
-4. The following adds the `gem` entry to the Gemfile without installing the
- gem. You can install gems later via `bundle install`.
-
- `bundle add rails --skip-install`
-
-5. You can assign the gem to more than one group.
-
- `bundle add rails --group "development, test"`
-
-## SEE ALSO
-
-[Gemfile(5)](https://bundler.io/man/gemfile.5.html),
-[bundle-remove(1)](bundle-remove.1.html)
diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1
index 56c9966e75..f5efe77e10 100644
--- a/lib/bundler/man/bundle-binstubs.1
+++ b/lib/bundler/man/bundle-binstubs.1
@@ -1,29 +1,41 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-BINSTUBS" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-BINSTUBS" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems
+.
.SH "SYNOPSIS"
\fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-path PATH] [\-\-standalone]
+.
.SH "DESCRIPTION"
Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into \fBbin/\fR\. Binstubs are a shortcut\-or alternative\- to always using \fBbundle exec\fR\. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application\.
+.
.P
For example, if you run \fBbundle binstubs rspec\-core\fR, Bundler will create the file \fBbin/rspec\fR\. That file will contain enough code to load Bundler, tell it to load the bundled gems, and then run rspec\.
+.
.P
This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the \fB\-\-path\fR directory if one has been set\. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-force\fR
Overwrite existing binstubs if they exist\.
+.
.TP
\fB\-\-path\fR
The location to install the specified binstubs to\. This defaults to \fBbin\fR\.
+.
.TP
\fB\-\-standalone\fR
Makes binstubs that can work without depending on Rubygems or Bundler at runtime\.
+.
.TP
\fB\-\-shebang\fR
-Specify a different shebang executable name than the default (default 'ruby')
+Specify a different shebang executable name than the default (default \'ruby\')
+.
.TP
\fB\-\-all\fR
Create binstubs for all gems in the bundle\.
diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1
index d634eef203..a17f1a6b06 100644
--- a/lib/bundler/man/bundle-cache.1
+++ b/lib/bundler/man/bundle-cache.1
@@ -1,40 +1,61 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CACHE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CACHE" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application
+.
.SH "SYNOPSIS"
\fBbundle cache\fR
+.
.P
alias: \fBpackage\fR, \fBpack\fR
+.
.SH "DESCRIPTION"
-Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR, use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\.
+Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running [bundle install(1)][bundle\-install], use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\.
+.
.SH "GIT AND PATH GEMS"
The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This needs to be explicitly enabled via the \fB\-\-all\fR option\. Once used, the \fB\-\-all\fR option will be remembered\.
+.
.SH "SUPPORT FOR MULTIPLE PLATFORMS"
When using gems that have different packages for different platforms, Bundler supports caching of gems for other platforms where the Gemfile has been resolved (i\.e\. present in the lockfile) in \fBvendor/cache\fR\. This needs to be enabled via the \fB\-\-all\-platforms\fR option\. This setting will be remembered in your local bundler configuration\.
+.
.SH "REMOTE FETCHING"
-By default, if you run \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR after running bundle cache(1) \fIbundle\-cache\.1\.html\fR, bundler will still connect to \fBrubygems\.org\fR to check whether a platform\-specific gem exists for any of the gems in \fBvendor/cache\fR\.
+By default, if you run \fBbundle install(1)\fR](bundle\-install\.1\.html) after running bundle cache(1) \fIbundle\-cache\.1\.html\fR, bundler will still connect to \fBrubygems\.org\fR to check whether a platform\-specific gem exists for any of the gems in \fBvendor/cache\fR\.
+.
.P
For instance, consider this Gemfile(5):
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
gem "nokogiri"
+.
.fi
+.
.IP "" 0
+.
.P
If you run \fBbundle cache\fR under C Ruby, bundler will retrieve the version of \fBnokogiri\fR for the \fB"ruby"\fR platform\. If you deploy to JRuby and run \fBbundle install\fR, bundler is forced to check to see whether a \fB"java"\fR platformed \fBnokogiri\fR exists\.
+.
.P
Even though the \fBnokogiri\fR gem for the Ruby platform is \fItechnically\fR acceptable on JRuby, it has a C extension that does not run on JRuby\. As a result, bundler will, by default, still connect to \fBrubygems\.org\fR to check whether it has a version of one of your gems more specific to your platform\.
+.
.P
This problem is also not limited to the \fB"java"\fR platform\. A similar (common) problem can happen when developing on Windows and deploying to Linux, or even when developing on OSX and deploying to Linux\.
+.
.P
If you know for sure that the gems packaged in \fBvendor/cache\fR are appropriate for the platform you are on, you can run \fBbundle install \-\-local\fR to skip checking for more appropriate gems, and use the ones in \fBvendor/cache\fR\.
+.
.P
One way to be sure that you have the right platformed versions of all your gems is to run \fBbundle cache\fR on an identical machine and check in the gems\. For instance, you can run \fBbundle cache\fR on an identical staging box during your staging process, and check in the \fBvendor/cache\fR before deploying to production\.
+.
.P
By default, bundle cache(1) \fIbundle\-cache\.1\.html\fR fetches and also installs the gems to the default location\. To package the dependencies to \fBvendor/cache\fR without installing them to the local install location, you can run \fBbundle cache \-\-no\-install\fR\.
+.
.SH "HISTORY"
In Bundler 2\.1, \fBcache\fR took in the functionalities of \fBpackage\fR and now \fBpackage\fR and \fBpack\fR are aliases of \fBcache\fR\.
diff --git a/lib/bundler/man/bundle-cache.1.ronn b/lib/bundler/man/bundle-cache.1.ronn
index 8112c2c551..46906d2b48 100644
--- a/lib/bundler/man/bundle-cache.1.ronn
+++ b/lib/bundler/man/bundle-cache.1.ronn
@@ -10,7 +10,7 @@ alias: `package`, `pack`
## DESCRIPTION
Copy all of the `.gem` files needed to run the application into the
-`vendor/cache` directory. In the future, when running [`bundle install(1)`](bundle-install.1.html),
+`vendor/cache` directory. In the future, when running [bundle install(1)][bundle-install],
use the gems in the cache in preference to the ones on `rubygems.org`.
## GIT AND PATH GEMS
@@ -29,7 +29,7 @@ bundler configuration.
## REMOTE FETCHING
-By default, if you run [`bundle install(1)`](bundle-install.1.html) after running
+By default, if you run `bundle install(1)`](bundle-install.1.html) after running
[bundle cache(1)](bundle-cache.1.html), bundler will still connect to `rubygems.org`
to check whether a platform-specific gem exists for any of the gems
in `vendor/cache`.
diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1
index e15a41e4fd..f1bf0b1821 100644
--- a/lib/bundler/man/bundle-check.1
+++ b/lib/bundler/man/bundle-check.1
@@ -1,23 +1,30 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CHECK" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CHECK" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems
+.
.SH "SYNOPSIS"
\fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE] [\-\-path=PATH]
+.
.SH "DESCRIPTION"
\fBcheck\fR searches the local machine for each of the gems requested in the Gemfile\. If all gems are found, Bundler prints a success message and exits with a status of 0\.
+.
.P
If not, the first missing gem is listed and Bundler exits status 1\.
-.P
-If the lockfile needs to be updated then it will be resolved using the gems installed on the local machine, if they satisfy the requirements\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-dry\-run\fR
Locks the [\fBGemfile(5)\fR][Gemfile(5)] before running the command\.
+.
.TP
\fB\-\-gemfile\fR
Use the specified gemfile instead of the [\fBGemfile(5)\fR][Gemfile(5)]\.
+.
.TP
\fB\-\-path\fR
Specify a different path than the system default (\fB$BUNDLE_PATH\fR or \fB$GEM_HOME\fR)\. Bundler will remember this value for future installs on this machine\.
diff --git a/lib/bundler/man/bundle-check.1.ronn b/lib/bundler/man/bundle-check.1.ronn
index eb3ff1daf9..f2846b8ff2 100644
--- a/lib/bundler/man/bundle-check.1.ronn
+++ b/lib/bundler/man/bundle-check.1.ronn
@@ -15,9 +15,6 @@ a status of 0.
If not, the first missing gem is listed and Bundler exits status 1.
-If the lockfile needs to be updated then it will be resolved using the gems
-installed on the local machine, if they satisfy the requirements.
-
## OPTIONS
* `--dry-run`:
diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1
index aa5ccf7594..b05a8eb0eb 100644
--- a/lib/bundler/man/bundle-clean.1
+++ b/lib/bundler/man/bundle-clean.1
@@ -1,16 +1,23 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CLEAN" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CLEAN" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory
+.
.SH "SYNOPSIS"
\fBbundle clean\fR [\-\-dry\-run] [\-\-force]
+.
.SH "DESCRIPTION"
This command will remove all unused gems in your bundler directory\. This is useful when you have made many changes to your gem dependencies\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-dry\-run\fR
Print the changes, but do not clean the unused gems\.
+.
.TP
\fB\-\-force\fR
Forces cleaning up unused gems even if Bundler is configured to use globally installed gems\. As a consequence, removes all system gems except for the ones in the current application\.
diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1
index 47104fb5c6..fdb06c321d 100644
--- a/lib/bundler/man/bundle-config.1
+++ b/lib/bundler/man/bundle-config.1
@@ -1,319 +1,515 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CONFIG" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CONFIG" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-config\fR \- Set bundler configuration options
+.
.SH "SYNOPSIS"
\fBbundle config\fR list
+.
.br
\fBbundle config\fR [get] NAME
+.
.br
\fBbundle config\fR [set] NAME VALUE
+.
.br
\fBbundle config\fR unset NAME
+.
.SH "DESCRIPTION"
-This command allows you to interact with Bundler's configuration system\.
+This command allows you to interact with Bundler\'s configuration system\.
+.
.P
Bundler loads configuration settings in this order:
+.
.IP "1." 4
Local config (\fB<project_root>/\.bundle/config\fR or \fB$BUNDLE_APP_CONFIG/config\fR)
+.
.IP "2." 4
Environmental variables (\fBENV\fR)
+.
.IP "3." 4
Global config (\fB~/\.bundle/config\fR)
+.
.IP "4." 4
Bundler default config
+.
.IP "" 0
+.
.P
Executing \fBbundle config list\fR will print a list of all bundler configuration for the current bundle, and where that configuration was set\.
+.
.P
Executing \fBbundle config get <name>\fR will print the value of that configuration setting, and where it was set\.
+.
.P
Executing \fBbundle config set <name> <value>\fR defaults to setting \fBlocal\fR configuration if executing from within a local application, otherwise it will set \fBglobal\fR configuration\. See \fB\-\-local\fR and \fB\-\-global\fR options below\.
+.
.P
Executing \fBbundle config set \-\-local <name> <value>\fR will set that configuration in the directory for the local application\. The configuration will be stored in \fB<project_root>/\.bundle/config\fR\. If \fBBUNDLE_APP_CONFIG\fR is set, the configuration will be stored in \fB$BUNDLE_APP_CONFIG/config\fR\.
+.
.P
Executing \fBbundle config set \-\-global <name> <value>\fR will set that configuration to the value specified for all bundles executed as the current user\. The configuration will be stored in \fB~/\.bundle/config\fR\. If \fIname\fR already is set, \fIname\fR will be overridden and user will be warned\.
+.
.P
Executing \fBbundle config unset <name>\fR will delete the configuration in both local and global sources\.
+.
.P
Executing \fBbundle config unset \-\-global <name>\fR will delete the configuration only from the user configuration\.
+.
.P
Executing \fBbundle config unset \-\-local <name>\fR will delete the configuration only from the local application\.
+.
.P
Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\.
+.
.SH "REMEMBERING OPTIONS"
-Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application's configuration (normally, \fB\./\.bundle/config\fR)\.
+Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application\'s configuration (normally, \fB\./\.bundle/config\fR)\.
+.
.P
-However, this will be changed in bundler 3, so it's better not to rely on this behavior\. If these options must be remembered, it's better to set them using \fBbundle config\fR (e\.g\., \fBbundle config set \-\-local path foo\fR)\.
+However, this will be changed in bundler 3, so it\'s better not to rely on this behavior\. If these options must be remembered, it\'s better to set them using \fBbundle config\fR (e\.g\., \fBbundle config set \-\-local path foo\fR)\.
+.
.P
The options that can be configured are:
+.
.TP
\fBbin\fR
-Creates a directory (defaults to \fB~/bin\fR) and place any executables from the gem there\. These executables run in Bundler's context\. If used, you might add this directory to your environment's \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
+Creates a directory (defaults to \fB~/bin\fR) and place any executables from the gem there\. These executables run in Bundler\'s context\. If used, you might add this directory to your environment\'s \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
+.
.TP
\fBdeployment\fR
-In deployment mode, Bundler will 'roll\-out' the bundle for \fBproduction\fR use\. Please check carefully if you want to have this option enabled in \fBdevelopment\fR or \fBtest\fR environments\.
+In deployment mode, Bundler will \'roll\-out\' the bundle for \fBproduction\fR use\. Please check carefully if you want to have this option enabled in \fBdevelopment\fR or \fBtest\fR environments\.
+.
.TP
\fBonly\fR
A space\-separated list of groups to install only gems of the specified groups\.
+.
.TP
\fBpath\fR
-The location to install the specified gems to\. This defaults to Rubygems' setting\. Bundler shares this location with Rubygems, \fBgem install \|\.\|\.\|\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \|\.\|\.\|\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\.
+The location to install the specified gems to\. This defaults to Rubygems\' setting\. Bundler shares this location with Rubygems, \fBgem install \.\.\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \.\.\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\.
+.
.TP
\fBwithout\fR
A space\-separated list of groups referencing gems to skip during installation\.
+.
.TP
\fBwith\fR
A space\-separated list of \fBoptional\fR groups referencing gems to include during installation\.
+.
.SH "BUILD OPTIONS"
You can use \fBbundle config\fR to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem\.
+.
.P
A very common example, the \fBmysql\fR gem, requires Snow Leopard users to pass configuration flags to \fBgem install\fR to specify where to find the \fBmysql_config\fR executable\.
+.
.IP "" 4
+.
.nf
+
gem install mysql \-\- \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config
+.
.fi
+.
.IP "" 0
+.
.P
Since the specific location of that executable can change from machine to machine, you can specify these flags on a per\-machine basis\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global build\.mysql \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config
+.
.fi
+.
.IP "" 0
+.
.P
After running this command, every time bundler needs to install the \fBmysql\fR gem, it will pass along the flags you specified\.
+.
.SH "CONFIGURATION KEYS"
Configuration keys in bundler have two forms: the canonical form and the environment variable form\.
+.
.P
-For instance, passing the \fB\-\-without\fR flag to bundle install(1) \fIbundle\-install\.1\.html\fR prevents Bundler from installing certain groups specified in the Gemfile(5)\. Bundler persists this value in \fBapp/\.bundle/config\fR so that calls to \fBBundler\.setup\fR do not try to find gems from the \fBGemfile\fR that you didn't install\. Additionally, subsequent calls to bundle install(1) \fIbundle\-install\.1\.html\fR remember this setting and skip those groups\.
+For instance, passing the \fB\-\-without\fR flag to bundle install(1) \fIbundle\-install\.1\.html\fR prevents Bundler from installing certain groups specified in the Gemfile(5)\. Bundler persists this value in \fBapp/\.bundle/config\fR so that calls to \fBBundler\.setup\fR do not try to find gems from the \fBGemfile\fR that you didn\'t install\. Additionally, subsequent calls to bundle install(1) \fIbundle\-install\.1\.html\fR remember this setting and skip those groups\.
+.
.P
The canonical form of this configuration is \fB"without"\fR\. To convert the canonical form to the environment variable form, capitalize it, and prepend \fBBUNDLE_\fR\. The environment variable form of \fB"without"\fR is \fBBUNDLE_WITHOUT\fR\.
+.
.P
Any periods in the configuration keys must be replaced with two underscores when setting it via environment variables\. The configuration key \fBlocal\.rack\fR becomes the environment variable \fBBUNDLE_LOCAL__RACK\fR\.
+.
.SH "LIST OF AVAILABLE KEYS"
The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\.
+.
+.IP "\(bu" 4
+\fBallow_deployment_source_credential_changes\fR (\fBBUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES\fR): When in deployment mode, allow changing the credentials to a gem\'s source\. Ex: \fBhttps://some\.host\.com/gems/path/\fR \-> \fBhttps://user_name:password@some\.host\.com/gems/path\fR
+.
.IP "\(bu" 4
\fBallow_offline_install\fR (\fBBUNDLE_ALLOW_OFFLINE_INSTALL\fR): Allow Bundler to use cached data when installing without network access\.
+.
.IP "\(bu" 4
\fBauto_clean_without_path\fR (\fBBUNDLE_AUTO_CLEAN_WITHOUT_PATH\fR): Automatically run \fBbundle clean\fR after installing when an explicit \fBpath\fR has not been set and Bundler is not installing into the system gems\.
+.
.IP "\(bu" 4
\fBauto_install\fR (\fBBUNDLE_AUTO_INSTALL\fR): Automatically run \fBbundle install\fR when gems are missing\.
+.
.IP "\(bu" 4
\fBbin\fR (\fBBUNDLE_BIN\fR): Install executables from gems in the bundle to the specified directory\. Defaults to \fBfalse\fR\.
+.
.IP "\(bu" 4
\fBcache_all\fR (\fBBUNDLE_CACHE_ALL\fR): Cache all gems, including path and git gems\. This needs to be explicitly configured on bundler 1 and bundler 2, but will be the default on bundler 3\.
+.
.IP "\(bu" 4
\fBcache_all_platforms\fR (\fBBUNDLE_CACHE_ALL_PLATFORMS\fR): Cache gems for all platforms\.
+.
.IP "\(bu" 4
\fBcache_path\fR (\fBBUNDLE_CACHE_PATH\fR): The directory that bundler will place cached gems in when running \fBbundle package\fR, and that bundler will look in when installing gems\. Defaults to \fBvendor/cache\fR\.
+.
.IP "\(bu" 4
\fBclean\fR (\fBBUNDLE_CLEAN\fR): Whether Bundler should run \fBbundle clean\fR automatically after \fBbundle install\fR\.
+.
.IP "\(bu" 4
\fBconsole\fR (\fBBUNDLE_CONSOLE\fR): The console that \fBbundle console\fR starts\. Defaults to \fBirb\fR\.
+.
.IP "\(bu" 4
\fBdefault_install_uses_path\fR (\fBBUNDLE_DEFAULT_INSTALL_USES_PATH\fR): Whether a \fBbundle install\fR without an explicit \fB\-\-path\fR argument defaults to installing gems in \fB\.bundle\fR\.
+.
.IP "\(bu" 4
\fBdeployment\fR (\fBBUNDLE_DEPLOYMENT\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\.
+.
.IP "\(bu" 4
\fBdisable_checksum_validation\fR (\fBBUNDLE_DISABLE_CHECKSUM_VALIDATION\fR): Allow installing gems even if they do not match the checksum provided by RubyGems\.
+.
.IP "\(bu" 4
\fBdisable_exec_load\fR (\fBBUNDLE_DISABLE_EXEC_LOAD\fR): Stop Bundler from using \fBload\fR to launch an executable in\-process in \fBbundle exec\fR\.
+.
.IP "\(bu" 4
\fBdisable_local_branch_check\fR (\fBBUNDLE_DISABLE_LOCAL_BRANCH_CHECK\fR): Allow Bundler to use a local git override without a branch specified in the Gemfile\.
+.
.IP "\(bu" 4
\fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\.
+.
.IP "\(bu" 4
-\fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems' normal location\.
+\fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems\' normal location\.
+.
.IP "\(bu" 4
\fBdisable_version_check\fR (\fBBUNDLE_DISABLE_VERSION_CHECK\fR): Stop Bundler from checking if a newer Bundler version is available on rubygems\.org\.
+.
.IP "\(bu" 4
-\fBforce_ruby_platform\fR (\fBBUNDLE_FORCE_RUBY_PLATFORM\fR): Ignore the current machine's platform and install only \fBruby\fR platform gems\. As a result, gems with native extensions will be compiled from source\.
+\fBforce_ruby_platform\fR (\fBBUNDLE_FORCE_RUBY_PLATFORM\fR): Ignore the current machine\'s platform and install only \fBruby\fR platform gems\. As a result, gems with native extensions will be compiled from source\.
+.
.IP "\(bu" 4
\fBfrozen\fR (\fBBUNDLE_FROZEN\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\. Defaults to \fBtrue\fR when \fB\-\-deployment\fR is used\.
+.
.IP "\(bu" 4
\fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in \fBREADME\fR file when you create a new gem via \fBbundle gem\fR command\. It can be overridden by passing an explicit \fB\-\-github\-username\fR flag to \fBbundle gem\fR\.
+.
.IP "\(bu" 4
\fBgem\.push_key\fR (\fBBUNDLE_GEM__PUSH_KEY\fR): Sets the \fB\-\-key\fR parameter for \fBgem push\fR when using the \fBrake release\fR command with a private gemstash server\.
+.
.IP "\(bu" 4
\fBgemfile\fR (\fBBUNDLE_GEMFILE\fR): The name of the file that bundler should use as the \fBGemfile\fR\. This location of this file also sets the root of the project, which is used to resolve relative paths in the \fBGemfile\fR, among other things\. By default, bundler will search up from the current working directory until it finds a \fBGemfile\fR\.
+.
.IP "\(bu" 4
\fBglobal_gem_cache\fR (\fBBUNDLE_GLOBAL_GEM_CACHE\fR): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation\.
+.
.IP "\(bu" 4
\fBignore_funding_requests\fR (\fBBUNDLE_IGNORE_FUNDING_REQUESTS\fR): When set, no funding requests will be printed\.
+.
.IP "\(bu" 4
\fBignore_messages\fR (\fBBUNDLE_IGNORE_MESSAGES\fR): When set, no post install messages will be printed\. To silence a single gem, use dot notation like \fBignore_messages\.httparty true\fR\.
+.
.IP "\(bu" 4
\fBinit_gems_rb\fR (\fBBUNDLE_INIT_GEMS_RB\fR): Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\.
+.
.IP "\(bu" 4
\fBjobs\fR (\fBBUNDLE_JOBS\fR): The number of gems Bundler can install in parallel\. Defaults to the number of available processors\.
+.
.IP "\(bu" 4
\fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR): Whether \fBbundle package\fR should skip installing gems\.
+.
.IP "\(bu" 4
\fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR): Whether Bundler should leave outdated gems unpruned when caching\.
+.
.IP "\(bu" 4
\fBonly\fR (\fBBUNDLE_ONLY\fR): A space\-separated list of groups to install only gems of the specified groups\.
+.
.IP "\(bu" 4
\fBpath\fR (\fBBUNDLE_PATH\fR): The location on disk where all gems in your bundle will be located regardless of \fB$GEM_HOME\fR or \fB$GEM_PATH\fR values\. Bundle gems not found in this location will be installed by \fBbundle install\fR\. Defaults to \fBGem\.dir\fR\. When \-\-deployment is used, defaults to vendor/bundle\.
+.
.IP "\(bu" 4
\fBpath\.system\fR (\fBBUNDLE_PATH__SYSTEM\fR): Whether Bundler will install gems into the default system path (\fBGem\.dir\fR)\.
+.
.IP "\(bu" 4
\fBpath_relative_to_cwd\fR (\fBBUNDLE_PATH_RELATIVE_TO_CWD\fR) Makes \fB\-\-path\fR relative to the CWD instead of the \fBGemfile\fR\.
+.
.IP "\(bu" 4
-\fBplugins\fR (\fBBUNDLE_PLUGINS\fR): Enable Bundler's experimental plugin system\.
+\fBplugins\fR (\fBBUNDLE_PLUGINS\fR): Enable Bundler\'s experimental plugin system\.
+.
.IP "\(bu" 4
\fBprefer_patch\fR (BUNDLE_PREFER_PATCH): Prefer updating only to next patch version during updates\. Makes \fBbundle update\fR calls equivalent to \fBbundler update \-\-patch\fR\.
+.
.IP "\(bu" 4
\fBprint_only_version_number\fR (\fBBUNDLE_PRINT_ONLY_VERSION_NUMBER\fR): Print only version number from \fBbundler \-\-version\fR\.
+.
.IP "\(bu" 4
\fBredirect\fR (\fBBUNDLE_REDIRECT\fR): The number of redirects allowed for network requests\. Defaults to \fB5\fR\.
+.
.IP "\(bu" 4
\fBretry\fR (\fBBUNDLE_RETRY\fR): The number of times to retry failed network requests\. Defaults to \fB3\fR\.
+.
.IP "\(bu" 4
\fBsetup_makes_kernel_gem_public\fR (\fBBUNDLE_SETUP_MAKES_KERNEL_GEM_PUBLIC\fR): Have \fBBundler\.setup\fR make the \fBKernel#gem\fR method public, even though RubyGems declares it as private\.
+.
.IP "\(bu" 4
\fBshebang\fR (\fBBUNDLE_SHEBANG\fR): The program name that should be invoked for generated binstubs\. Defaults to the ruby install name used to generate the binstub\.
+.
.IP "\(bu" 4
\fBsilence_deprecations\fR (\fBBUNDLE_SILENCE_DEPRECATIONS\fR): Whether Bundler should silence deprecation warnings for behavior that will be changed in the next major version\.
+.
.IP "\(bu" 4
\fBsilence_root_warning\fR (\fBBUNDLE_SILENCE_ROOT_WARNING\fR): Silence the warning Bundler prints when installing gems as root\.
+.
.IP "\(bu" 4
\fBssl_ca_cert\fR (\fBBUNDLE_SSL_CA_CERT\fR): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format\.
+.
.IP "\(bu" 4
\fBssl_client_cert\fR (\fBBUNDLE_SSL_CLIENT_CERT\fR): Path to a designated file containing a X\.509 client certificate and key in PEM format\.
+.
.IP "\(bu" 4
\fBssl_verify_mode\fR (\fBBUNDLE_SSL_VERIFY_MODE\fR): The SSL verification mode Bundler uses when making HTTPS requests\. Defaults to verify peer\.
+.
+.IP "\(bu" 4
+\fBsuppress_install_using_messages\fR (\fBBUNDLE_SUPPRESS_INSTALL_USING_MESSAGES\fR): Avoid printing \fBUsing \.\.\.\fR messages during installation when the version of a gem has not changed\.
+.
.IP "\(bu" 4
\fBsystem_bindir\fR (\fBBUNDLE_SYSTEM_BINDIR\fR): The location where RubyGems installs binstubs\. Defaults to \fBGem\.bindir\fR\.
+.
.IP "\(bu" 4
\fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\.
+.
.IP "\(bu" 4
\fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\.
+.
.IP "\(bu" 4
\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
\fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A \fB:\fR\-separated list of groups whose gems bundler should not install\.
+.
.IP "" 0
+.
.P
In general, you should set these settings per\-application by using the applicable flag to the bundle install(1) \fIbundle\-install\.1\.html\fR or bundle cache(1) \fIbundle\-cache\.1\.html\fR command\.
+.
.P
You can set them globally either via environment variables or \fBbundle config\fR, whichever is preferable for your setup\. If you use both, environment variables will take preference over global settings\.
+.
.SH "LOCAL GIT REPOS"
Bundler also allows you to work against a git repository locally instead of using the remote version\. This can be achieved by setting up a local override:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-local local\.GEM_NAME /path/to/local/git/repository
+.
.fi
+.
.IP "" 0
+.
.P
For example, in order to use a local Rack repository, a developer could call:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-local local\.rack ~/Work/git/rack
+.
.fi
+.
.IP "" 0
+.
.P
-Now instead of checking out the remote git repository, the local override will be used\. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler\. This means a commit in the local git repo will update the revision in the \fBGemfile\.lock\fR to the local git repo revision\. This requires the same attention as git submodules\. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine\. You'll also need to CGI escape your usernames and passwords as well\.
+Now instead of checking out the remote git repository, the local override will be used\. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler\. This means a commit in the local git repo will update the revision in the \fBGemfile\.lock\fR to the local git repo revision\. This requires the same attention as git submodules\. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine\. You\'ll also need to CGI escape your usernames and passwords as well\.
+.
.P
-Bundler does many checks to ensure a developer won't work with invalid references\. Particularly, we force a developer to specify a branch in the \fBGemfile\fR in order to use this feature\. If the branch specified in the \fBGemfile\fR and the current branch in the local git repository do not match, Bundler will abort\. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch\.
+Bundler does many checks to ensure a developer won\'t work with invalid references\. Particularly, we force a developer to specify a branch in the \fBGemfile\fR in order to use this feature\. If the branch specified in the \fBGemfile\fR and the current branch in the local git repository do not match, Bundler will abort\. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch\.
+.
.P
Finally, Bundler also ensures that the current revision in the \fBGemfile\.lock\fR exists in the local git repository\. By doing this, Bundler forces you to fetch the latest changes in the remotes\.
+.
.SH "MIRRORS OF GEM SOURCES"
Bundler supports overriding gem sources with mirrors\. This allows you to configure rubygems\.org as the gem source in your Gemfile while still using your mirror to fetch gems\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global mirror\.SOURCE_URL MIRROR_URL
+.
.fi
+.
.IP "" 0
+.
.P
For example, to use a mirror of https://rubygems\.org hosted at https://example\.org:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global mirror\.https://rubygems\.org https://example\.org
+.
.fi
+.
.IP "" 0
+.
.P
Each mirror also provides a fallback timeout setting\. If the mirror does not respond within the fallback timeout, Bundler will try to use the original server instead of the mirror\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global mirror\.SOURCE_URL\.fallback_timeout TIMEOUT
+.
.fi
+.
.IP "" 0
+.
.P
For example, to fall back to rubygems\.org after 3 seconds:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global mirror\.https://rubygems\.org\.fallback_timeout 3
+.
.fi
+.
.IP "" 0
+.
.P
The default fallback timeout is 0\.1 seconds, but the setting can currently only accept whole seconds (for example, 1, 15, or 30)\.
+.
.SH "CREDENTIALS FOR GEM SOURCES"
Bundler allows you to configure credentials for any gem source, which allows you to avoid putting secrets into your Gemfile\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global SOURCE_HOSTNAME USERNAME:PASSWORD
+.
.fi
+.
.IP "" 0
+.
.P
For example, to save the credentials of user \fBclaudette\fR for the gem source at \fBgems\.longerous\.com\fR, you would run:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global gems\.longerous\.com claudette:s00pers3krit
+.
.fi
+.
.IP "" 0
+.
.P
Or you can set the credentials as an environment variable like this:
+.
.IP "" 4
+.
.nf
+
export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit"
+.
.fi
+.
.IP "" 0
+.
.P
For gems with a git source with HTTP(S) URL you can specify credentials like so:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global https://github\.com/rubygems/rubygems\.git username:password
+.
.fi
+.
.IP "" 0
+.
.P
Or you can set the credentials as an environment variable like so:
+.
.IP "" 4
+.
.nf
+
export BUNDLE_GITHUB__COM=username:password
+.
.fi
+.
.IP "" 0
+.
.P
This is especially useful for private repositories on hosts such as GitHub, where you can use personal OAuth tokens:
+.
.IP "" 4
+.
.nf
+
export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x\-oauth\-basic
+.
.fi
+.
.IP "" 0
+.
.P
Note that any configured credentials will be redacted by informative commands such as \fBbundle config list\fR or \fBbundle config get\fR, unless you use the \fB\-\-parseable\fR flag\. This is to avoid unintentionally leaking credentials when copy\-pasting bundler output\.
+.
.P
Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations:
+.
.IP "\(bu" 4
-Any \fB\-\fR characters in a host name are mapped to a triple underscore (\fB___\fR) in the corresponding environment variable\.
+Any \fB\-\fR characters in a host name are mapped to a triple dash (\fB___\fR) in the corresponding environment variable\.
+.
.IP "\(bu" 4
-Any \fB\.\fR characters in a host name are mapped to a double underscore (\fB__\fR) in the corresponding environment variable\.
+Any \fB\.\fR characters in a host name are mapped to a double dash (\fB__\fR) in the corresponding environment variable\.
+.
.IP "" 0
+.
.P
-This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you'll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\.
+This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you\'ll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\.
+.
.SH "CONFIGURE BUNDLER DIRECTORIES"
-Bundler's home, cache and plugin directories and config file can be configured through environment variables\. The default location for Bundler's home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values
+Bundler\'s home, config, cache and plugin directories are able to be configured through environment variables\. The default location for Bundler\'s home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values
+.
.IP "" 4
+.
.nf
+
BUNDLE_USER_HOME : $HOME/\.bundle
BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache
BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config
BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin
+.
.fi
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn
index 1a0ec2a5dc..bc8b27cf89 100644
--- a/lib/bundler/man/bundle-config.1.ronn
+++ b/lib/bundler/man/bundle-config.1.ronn
@@ -137,6 +137,9 @@ the environment variable `BUNDLE_LOCAL__RACK`.
The following is a list of all configuration keys and their purpose. You can
learn more about their operation in [bundle install(1)](bundle-install.1.html).
+* `allow_deployment_source_credential_changes` (`BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES`):
+ When in deployment mode, allow changing the credentials to a gem's source.
+ Ex: `https://some.host.com/gems/path/` -> `https://user_name:password@some.host.com/gems/path`
* `allow_offline_install` (`BUNDLE_ALLOW_OFFLINE_INSTALL`):
Allow Bundler to use cached data when installing without network access.
* `auto_clean_without_path` (`BUNDLE_AUTO_CLEAN_WITHOUT_PATH`):
@@ -262,6 +265,9 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
* `ssl_verify_mode` (`BUNDLE_SSL_VERIFY_MODE`):
The SSL verification mode Bundler uses when making HTTPS requests.
Defaults to verify peer.
+* `suppress_install_using_messages` (`BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES`):
+ Avoid printing `Using ...` messages during installation when the version of
+ a gem has not changed.
* `system_bindir` (`BUNDLE_SYSTEM_BINDIR`):
The location where RubyGems installs binstubs. Defaults to `Gem.bindir`.
* `timeout` (`BUNDLE_TIMEOUT`):
@@ -271,12 +277,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`):
@@ -385,10 +385,10 @@ copy-pasting bundler output.
Also note that to guarantee a sane mapping between valid environment variable
names and valid host names, bundler makes the following transformations:
-* Any `-` characters in a host name are mapped to a triple underscore (`___`) in the
+* Any `-` characters in a host name are mapped to a triple dash (`___`) in the
corresponding environment variable.
-* Any `.` characters in a host name are mapped to a double underscore (`__`) in the
+* Any `.` characters in a host name are mapped to a double dash (`__`) in the
corresponding environment variable.
This means that if you have a gem server named `my.gem-host.com`, you'll need to
@@ -397,7 +397,7 @@ through ENV.
## CONFIGURE BUNDLER DIRECTORIES
-Bundler's home, cache and plugin directories and config file can be configured
+Bundler's home, config, cache and plugin directories are able to be configured
through environment variables. The default location for Bundler's home directory is
`~/.bundle`, which all directories inherit from by default. The following
outlines the available environment variables and their default values
diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1
index f2b2ddaed0..6cb0f0f810 100644
--- a/lib/bundler/man/bundle-console.1
+++ b/lib/bundler/man/bundle-console.1
@@ -1,35 +1,53 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CONSOLE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CONSOLE" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-console\fR \- Deprecated way to open an IRB session with the bundle pre\-loaded
+.
.SH "SYNOPSIS"
\fBbundle console\fR [GROUP]
+.
.SH "DESCRIPTION"
Starts an interactive Ruby console session in the context of the current bundle\.
+.
.P
If no \fBGROUP\fR is specified, all gems in the \fBdefault\fR group in the Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR are preliminarily loaded\.
+.
.P
If \fBGROUP\fR is specified, all gems in the given group in the Gemfile in addition to the gems in \fBdefault\fR group are loaded\. Even if the given group does not exist in the Gemfile, IRB console starts without any warning or error\.
+.
.P
The environment variable \fBBUNDLE_CONSOLE\fR or \fBbundle config set console\fR can be used to change the shell from the following:
+.
.IP "\(bu" 4
\fBirb\fR (default)
+.
.IP "\(bu" 4
\fBpry\fR (https://github\.com/pry/pry)
+.
.IP "\(bu" 4
\fBripl\fR (https://github\.com/cldwalker/ripl)
+.
.IP "" 0
+.
.P
\fBbundle console\fR uses irb by default\. An alternative Pry or Ripl can be used with \fBbundle console\fR by adjusting the \fBconsole\fR Bundler setting\. Also make sure that \fBpry\fR or \fBripl\fR is in your Gemfile\.
+.
.SH "EXAMPLE"
+.
.nf
+
$ bundle config set console pry
$ bundle console
-Resolving dependencies\|\.\|\.\|\.
+Resolving dependencies\.\.\.
[1] pry(main)>
+.
.fi
+.
.SH "NOTES"
This command was deprecated in Bundler 2\.1 and will be removed in 3\.0\. Use \fBbin/console\fR script, which can be generated by \fBbundle gem <NAME>\fR\.
+.
.SH "SEE ALSO"
Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR
diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1
index f225d0cd79..bfe928c9a1 100644
--- a/lib/bundler/man/bundle-doctor.1
+++ b/lib/bundler/man/bundle-doctor.1
@@ -1,30 +1,44 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-DOCTOR" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-DOCTOR" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-doctor\fR \- Checks the bundle for common problems
+.
.SH "SYNOPSIS"
\fBbundle doctor\fR [\-\-quiet] [\-\-gemfile=GEMFILE]
+.
.SH "DESCRIPTION"
Checks your Gemfile and gem environment for common problems\. If issues are detected, Bundler prints them and exits status 1\. Otherwise, Bundler prints a success message and exits status 0\.
+.
.P
Examples of common problems caught by bundle\-doctor include:
+.
.IP "\(bu" 4
Invalid Bundler settings
+.
.IP "\(bu" 4
Mismatched Ruby versions
+.
.IP "\(bu" 4
Mismatched platforms
+.
.IP "\(bu" 4
Uninstalled gems
+.
.IP "\(bu" 4
Missing dependencies
+.
.IP "" 0
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-quiet\fR
Only output warnings and errors\.
+.
.TP
\fB\-\-gemfile=<gemfile>\fR
-The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\.
+The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project\'s root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\.
diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1
index e16b7bc747..281f3faede 100644
--- a/lib/bundler/man/bundle-exec.1
+++ b/lib/bundler/man/bundle-exec.1
@@ -1,104 +1,165 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-EXEC" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-EXEC" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-exec\fR \- Execute a command in the context of the bundle
+.
.SH "SYNOPSIS"
\fBbundle exec\fR [\-\-keep\-file\-descriptors] \fIcommand\fR
+.
.SH "DESCRIPTION"
This command executes the command, making all gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] available to \fBrequire\fR in Ruby programs\.
+.
.P
Essentially, if you would normally have run something like \fBrspec spec/my_spec\.rb\fR, and you want to use the gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] and installed via bundle install(1) \fIbundle\-install\.1\.html\fR, you should run \fBbundle exec rspec spec/my_spec\.rb\fR\.
+.
.P
-Note that \fBbundle exec\fR does not require that an executable is available on your shell's \fB$PATH\fR\.
+Note that \fBbundle exec\fR does not require that an executable is available on your shell\'s \fB$PATH\fR\.
+.
.SH "OPTIONS"
+.
.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\.
+.
.P
After using \fB\-\-binstubs\fR, \fBbin/rspec spec/my_spec\.rb\fR is identical to \fBbundle exec rspec spec/my_spec\.rb\fR\.
+.
.SH "ENVIRONMENT MODIFICATIONS"
\fBbundle exec\fR makes a number of changes to the shell environment, then executes the command you specify in full\.
+.
.IP "\(bu" 4
-make sure that it's still possible to shell out to \fBbundle\fR from inside a command invoked by \fBbundle exec\fR (using \fB$BUNDLE_BIN_PATH\fR)
+make sure that it\'s still possible to shell out to \fBbundle\fR from inside a command invoked by \fBbundle exec\fR (using \fB$BUNDLE_BIN_PATH\fR)
+.
.IP "\(bu" 4
put the directory containing executables (like \fBrails\fR, \fBrspec\fR, \fBrackup\fR) for your bundle on \fB$PATH\fR
+.
.IP "\(bu" 4
make sure that if bundler is invoked in the subshell, it uses the same \fBGemfile\fR (by setting \fBBUNDLE_GEMFILE\fR)
+.
.IP "\(bu" 4
add \fB\-rbundler/setup\fR to \fB$RUBYOPT\fR, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle
+.
.IP "" 0
+.
.P
It also modifies Rubygems:
+.
.IP "\(bu" 4
disallow loading additional gems not in the bundle
+.
.IP "\(bu" 4
-modify the \fBgem\fR method to be a no\-op if a gem matching the requirements is in the bundle, and to raise a \fBGem::LoadError\fR if it's not
+modify the \fBgem\fR method to be a no\-op if a gem matching the requirements is in the bundle, and to raise a \fBGem::LoadError\fR if it\'s not
+.
.IP "\(bu" 4
Define \fBGem\.refresh\fR to be a no\-op, since the source index is always frozen when using bundler, and to prevent gems from the system leaking into the environment
+.
.IP "\(bu" 4
Override \fBGem\.bin_path\fR to use the gems in the bundle, making system executables work
+.
.IP "\(bu" 4
Add all gems in the bundle into Gem\.loaded_specs
+.
.IP "" 0
+.
.P
-Finally, \fBbundle exec\fR also implicitly modifies \fBGemfile\.lock\fR if the lockfile and the Gemfile do not match\. Bundler needs the Gemfile to determine things such as a gem's groups, \fBautorequire\fR, and platforms, etc\., and that information isn't stored in the lockfile\. The Gemfile and lockfile must be synced in order to \fBbundle exec\fR successfully, so \fBbundle exec\fR updates the lockfile beforehand\.
+Finally, \fBbundle exec\fR also implicitly modifies \fBGemfile\.lock\fR if the lockfile and the Gemfile do not match\. Bundler needs the Gemfile to determine things such as a gem\'s groups, \fBautorequire\fR, and platforms, etc\., and that information isn\'t stored in the lockfile\. The Gemfile and lockfile must be synced in order to \fBbundle exec\fR successfully, so \fBbundle exec\fR updates the lockfile beforehand\.
+.
.SS "Loading"
By default, when attempting to \fBbundle exec\fR to a file with a ruby shebang, Bundler will \fBKernel\.load\fR that file instead of using \fBKernel\.exec\fR\. For the vast majority of cases, this is a performance improvement\. In a rare few cases, this could cause some subtle side\-effects (such as dependence on the exact contents of \fB$0\fR or \fB__FILE__\fR) and the optimization can be disabled by enabling the \fBdisable_exec_load\fR setting\.
+.
.SS "Shelling out"
-Any Ruby code that opens a subshell (like \fBsystem\fR, backticks, or \fB%x{}\fR) will automatically use the current Bundler environment\. If you need to shell out to a Ruby command that is not part of your current bundle, use the \fBwith_unbundled_env\fR method with a block\. Any subshells created inside the block will be given the environment present before Bundler was activated\. For example, Homebrew commands run Ruby, but don't work inside a bundle:
+Any Ruby code that opens a subshell (like \fBsystem\fR, backticks, or \fB%x{}\fR) will automatically use the current Bundler environment\. If you need to shell out to a Ruby command that is not part of your current bundle, use the \fBwith_unbundled_env\fR method with a block\. Any subshells created inside the block will be given the environment present before Bundler was activated\. For example, Homebrew commands run Ruby, but don\'t work inside a bundle:
+.
.IP "" 4
+.
.nf
+
Bundler\.with_unbundled_env do
`brew install wget`
end
+.
.fi
+.
.IP "" 0
+.
.P
Using \fBwith_unbundled_env\fR is also necessary if you are shelling out to a different bundle\. Any Bundler commands run in a subshell will inherit the current Gemfile, so commands that need to run in the context of a different bundle also need to use \fBwith_unbundled_env\fR\.
+.
.IP "" 4
+.
.nf
+
Bundler\.with_unbundled_env do
Dir\.chdir "/other/bundler/project" do
`bundle exec \./script`
end
end
+.
.fi
+.
.IP "" 0
+.
.P
Bundler provides convenience helpers that wrap \fBsystem\fR and \fBexec\fR, and they can be used like this:
+.
.IP "" 4
+.
.nf
-Bundler\.clean_system('brew install wget')
-Bundler\.clean_exec('brew install wget')
+
+Bundler\.clean_system(\'brew install wget\')
+Bundler\.clean_exec(\'brew install wget\')
+.
.fi
+.
.IP "" 0
+.
.SH "RUBYGEMS PLUGINS"
At present, the Rubygems plugin system requires all files named \fBrubygems_plugin\.rb\fR on the load path of \fIany\fR installed gem when any Ruby code requires \fBrubygems\.rb\fR\. This includes executables installed into the system, like \fBrails\fR, \fBrackup\fR, and \fBrspec\fR\.
+.
.P
Since Rubygems plugins can contain arbitrary Ruby code, they commonly end up activating themselves or their dependencies\.
+.
.P
For instance, the \fBgemcutter 0\.5\fR gem depended on \fBjson_pure\fR\. If you had that version of gemcutter installed (even if you \fIalso\fR had a newer version without this problem), Rubygems would activate \fBgemcutter 0\.5\fR and \fBjson_pure <latest>\fR\.
+.
.P
If your Gemfile(5) also contained \fBjson_pure\fR (or a gem with a dependency on \fBjson_pure\fR), the latest version on your system might conflict with the version in your Gemfile(5), or the snapshot version in your \fBGemfile\.lock\fR\.
+.
.P
If this happens, bundler will say:
+.
.IP "" 4
+.
.nf
+
You have already activated json_pure 1\.4\.6 but your Gemfile
requires json_pure 1\.4\.3\. Consider using bundle exec\.
+.
.fi
+.
.IP "" 0
+.
.P
In this situation, you almost certainly want to remove the underlying gem with the problematic gem plugin\. In general, the authors of these plugins (in this case, the \fBgemcutter\fR gem) have released newer versions that are more careful in their plugins\.
+.
.P
You can find a list of all the gems containing gem plugins by running
+.
.IP "" 4
+.
.nf
-ruby \-e "puts Gem\.find_files('rubygems_plugin\.rb')"
+
+ruby \-e "puts Gem\.find_files(\'rubygems_plugin\.rb\')"
+.
.fi
+.
.IP "" 0
+.
.P
-At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren't using (\fBgem uninstall gem_name\fR)\.
+At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren\'t using (\fBgem uninstall gem_name\fR)\.
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 e6e58cd409..4bac1bf442 100644
--- a/lib/bundler/man/bundle-gem.1
+++ b/lib/bundler/man/bundle-gem.1
@@ -1,75 +1,105 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-GEM" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-GEM" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem
+.
.SH "SYNOPSIS"
\fBbundle gem\fR \fIGEM_NAME\fR \fIOPTIONS\fR
+.
.SH "DESCRIPTION"
Generates a directory named \fBGEM_NAME\fR with a \fBRakefile\fR, \fBGEM_NAME\.gemspec\fR, and other supporting files and directories that can be used to develop a rubygem with that name\.
+.
.P
Run \fBrake \-T\fR in the resulting project for a list of Rake tasks that can be used to test and publish the gem to rubygems\.org\.
+.
.P
-The generated project skeleton can be customized with OPTIONS, as explained below\. Note that these options can also be specified via Bundler's global configuration file using the following names:
+The generated project skeleton can be customized with OPTIONS, as explained below\. Note that these options can also be specified via Bundler\'s global configuration file using the following names:
+.
.IP "\(bu" 4
\fBgem\.coc\fR
+.
.IP "\(bu" 4
\fBgem\.mit\fR
+.
.IP "\(bu" 4
\fBgem\.test\fR
+.
.IP "" 0
+.
.SH "OPTIONS"
+.
.IP "\(bu" 4
\fB\-\-exe\fR or \fB\-b\fR or \fB\-\-bin\fR: Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\.
+.
.IP "\(bu" 4
\fB\-\-no\-exe\fR: Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\.
+.
.IP "\(bu" 4
-\fB\-\-coc\fR: Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
+\fB\-\-coc\fR: Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
\fB\-\-no\-coc\fR: Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\.
+.
.IP "\(bu" 4
\fB\-\-ext=c\fR, \fB\-\-ext=rust\fR Add boilerplate for C or Rust (currently magnus \fIhttps://docs\.rs/magnus\fR based) extension code to the generated project\. This behavior is disabled by default\.
+.
.IP "\(bu" 4
\fB\-\-no\-ext\fR: Do not add extension code (overrides \fB\-\-ext\fR specified in the global config)\.
+.
.IP "\(bu" 4
-\fB\-\-mit\fR: Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
+\fB\-\-mit\fR: Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
\fB\-\-no\-mit\fR: Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\.
+.
.IP "\(bu" 4
\fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR: Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified:
+.
.IP
-When Bundler is configured to generate tests, this defaults to Bundler's global config setting \fBgem\.test\fR\.
+When Bundler is configured to generate tests, this defaults to Bundler\'s global config setting \fBgem\.test\fR\.
+.
.IP
When Bundler is configured to not generate tests, an interactive prompt will be displayed and the answer will be used for the current rubygem project\.
+.
.IP
-When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
-.IP "\(bu" 4
-\fB\-\-no\-test\fR: Do not use a test framework (overrides \fB\-\-test\fR specified in the global config)\.
+When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
\fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR: Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified:
+.
.IP
-When Bundler is configured to generate CI files, this defaults to Bundler's global config setting \fBgem\.ci\fR\.
+When Bundler is configured to generate CI files, this defaults to Bundler\'s global config setting \fBgem\.ci\fR\.
+.
.IP
When Bundler is configured to not generate CI files, an interactive prompt will be displayed and the answer will be used for the current rubygem project\.
+.
.IP
-When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
-.IP "\(bu" 4
-\fB\-\-no\-ci\fR: Do not use a continuous integration service (overrides \fB\-\-ci\fR specified in the global config)\.
+When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
-\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR: Specify the linter and code formatter that Bundler should add to the project's development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified:
+\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR: Specify the linter and code formatter that Bundler should add to the project\'s development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified:
+.
.IP
-When Bundler is configured to add a linter, this defaults to Bundler's global config setting \fBgem\.linter\fR\.
+When Bundler is configured to add a linter, this defaults to Bundler\'s global config setting \fBgem\.linter\fR\.
+.
.IP
When Bundler is configured not to add a linter, an interactive prompt will be displayed and the answer will be used for the current rubygem project\.
+.
.IP
-When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
-.IP "\(bu" 4
-\fB\-\-no\-linter\fR: Do not add a linter (overrides \fB\-\-linter\fR specified in the global config)\.
+When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
\fB\-e\fR, \fB\-\-edit[=EDITOR]\fR: Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\.
+.
.IP "" 0
+.
.SH "SEE ALSO"
+.
.IP "\(bu" 4
bundle config(1) \fIbundle\-config\.1\.html\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-gem.1.ronn b/lib/bundler/man/bundle-gem.1.ronn
index 2d71d8dabe..46fa2f179f 100644
--- a/lib/bundler/man/bundle-gem.1.ronn
+++ b/lib/bundler/man/bundle-gem.1.ronn
@@ -76,10 +76,6 @@ configuration file using the following names:
the answer will be saved in Bundler's global config for future `bundle gem`
use.
-* `--no-test`:
- Do not use a test framework (overrides `--test` specified in the global
- config).
-
* `--ci`, `--ci=github`, `--ci=gitlab`, `--ci=circle`:
Specify the continuous integration service that Bundler should use when
generating the project. Acceptable values are `github`, `gitlab`
@@ -96,10 +92,6 @@ configuration file using the following names:
the answer will be saved in Bundler's global config for future `bundle gem`
use.
-* `--no-ci`:
- Do not use a continuous integration service (overrides `--ci` specified in
- the global config).
-
* `--linter`, `--linter=rubocop`, `--linter=standard`:
Specify the linter and code formatter that Bundler should add to the
project's development dependencies. Acceptable values are `rubocop` and
@@ -116,9 +108,6 @@ configuration file using the following names:
the answer will be saved in Bundler's global config for future `bundle gem`
use.
-* `--no-linter`:
- Do not add a linter (overrides `--linter` specified in the global config).
-
* `-e`, `--edit[=EDITOR]`:
Open the resulting GEM_NAME.gemspec in EDITOR, or the default editor if not
specified. The default is `$BUNDLER_EDITOR`, `$VISUAL`, or `$EDITOR`.
diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1
index d7a05f824e..47a42a497e 100644
--- a/lib/bundler/man/bundle-help.1
+++ b/lib/bundler/man/bundle-help.1
@@ -1,9 +1,13 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-HELP" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-HELP" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-help\fR \- Displays detailed help for each subcommand
+.
.SH "SYNOPSIS"
\fBbundle help\fR [COMMAND]
+.
.SH "DESCRIPTION"
Displays detailed help for the given subcommand\. You can specify a single \fBCOMMAND\fR at the same time\. When \fBCOMMAND\fR is omitted, help for \fBhelp\fR command will be displayed\.
diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1
index 6b401a57f4..e9f5583e85 100644
--- a/lib/bundler/man/bundle-info.1
+++ b/lib/bundler/man/bundle-info.1
@@ -1,13 +1,19 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INFO" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-INFO" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-info\fR \- Show information for the given gem in your bundle
+.
.SH "SYNOPSIS"
-\fBbundle info\fR [GEM_NAME] [\-\-path]
+\fBbundle info\fR [GEM] [\-\-path]
+.
.SH "DESCRIPTION"
-Given a gem name present in your bundle, print the basic information about it such as homepage, version, path and summary\.
+Print the basic information about the provided GEM such as homepage, version, path and summary\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-path\fR
Print the path of the given gem
diff --git a/lib/bundler/man/bundle-info.1.ronn b/lib/bundler/man/bundle-info.1.ronn
index cecdeb564f..47e457aa3c 100644
--- a/lib/bundler/man/bundle-info.1.ronn
+++ b/lib/bundler/man/bundle-info.1.ronn
@@ -3,13 +3,13 @@ bundle-info(1) -- Show information for the given gem in your bundle
## SYNOPSIS
-`bundle info` [GEM_NAME]
+`bundle info` [GEM]
[--path]
## DESCRIPTION
-Given a gem name present in your bundle, print the basic information about it
- such as homepage, version, path and summary.
+Print the basic information about the provided GEM such as homepage, version,
+path and summary.
## OPTIONS
diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1
index f2e444c7c2..9e8b059f1f 100644
--- a/lib/bundler/man/bundle-init.1
+++ b/lib/bundler/man/bundle-init.1
@@ -1,20 +1,25 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INIT" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-INIT" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-init\fR \- Generates a Gemfile into the current working directory
+.
.SH "SYNOPSIS"
\fBbundle init\fR [\-\-gemspec=FILE]
+.
.SH "DESCRIPTION"
Init generates a default [\fBGemfile(5)\fR][Gemfile(5)] in the current working directory\. When adding a [\fBGemfile(5)\fR][Gemfile(5)] to a gem with a gemspec, the \fB\-\-gemspec\fR option will automatically add each dependency listed in the gemspec file to the newly created [\fBGemfile(5)\fR][Gemfile(5)]\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-gemspec\fR
Use the specified \.gemspec to create the [\fBGemfile(5)\fR][Gemfile(5)]
-.TP
-\fB\-\-gemfile\fR
-Use the specified name for the gemfile instead of \fBGemfile\fR
+.
.SH "FILES"
Included in the default [\fBGemfile(5)\fR][Gemfile(5)] generated is the line \fB# frozen_string_literal: true\fR\. This is a magic comment supported for the first time in Ruby 2\.3\. The presence of this line results in all string literals in the file being implicitly frozen\.
+.
.SH "SEE ALSO"
Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR
diff --git a/lib/bundler/man/bundle-init.1.ronn b/lib/bundler/man/bundle-init.1.ronn
index 7d3cede1f6..9d3d97deea 100644
--- a/lib/bundler/man/bundle-init.1.ronn
+++ b/lib/bundler/man/bundle-init.1.ronn
@@ -16,8 +16,6 @@ created [`Gemfile(5)`][Gemfile(5)].
* `--gemspec`:
Use the specified .gemspec to create the [`Gemfile(5)`][Gemfile(5)]
-* `--gemfile`:
- Use the specified name for the gemfile instead of `Gemfile`
## FILES
diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1
index 8eb3633837..0b0766a40c 100644
--- a/lib/bundler/man/bundle-inject.1
+++ b/lib/bundler/man/bundle-inject.1
@@ -1,23 +1,36 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INJECT" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-INJECT" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile
+.
.SH "SYNOPSIS"
\fBbundle inject\fR [GEM] [VERSION]
+.
.SH "DESCRIPTION"
Adds the named gem(s) with their version requirements to the resolved [\fBGemfile(5)\fR][Gemfile(5)]\.
+.
.P
-This command will add the gem to both your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock if it isn't listed yet\.
+This command will add the gem to both your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock if it isn\'t listed yet\.
+.
.P
Example:
+.
.IP "" 4
+.
.nf
+
bundle install
-bundle inject 'rack' '> 0'
+bundle inject \'rack\' \'> 0\'
+.
.fi
+.
.IP "" 0
+.
.P
-This will inject the 'rack' gem with a version greater than 0 in your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock\.
+This will inject the \'rack\' gem with a version greater than 0 in your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock\.
+.
.P
The \fBbundle inject\fR command was deprecated in Bundler 2\.1 and will be removed in Bundler 3\.0\.
diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1
index 7539d18f81..fcf6a6a66c 100644
--- a/lib/bundler/man/bundle-install.1
+++ b/lib/bundler/man/bundle-install.1
@@ -1,215 +1,313 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INSTALL" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-INSTALL" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-install\fR \- Install the dependencies specified in your Gemfile
+.
.SH "SYNOPSIS"
-\fBbundle install\fR [\-\-binstubs[=DIRECTORY]] [\-\-clean] [\-\-deployment] [\-\-frozen] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-no\-cache] [\-\-no\-prune] [\-\-path PATH] [\-\-prefer\-local] [\-\-quiet] [\-\-redownload] [\-\-retry=NUMBER] [\-\-shebang] [\-\-standalone[=GROUP[ GROUP\|\.\|\.\|\.]]] [\-\-system] [\-\-trust\-policy=POLICY] [\-\-with=GROUP[ GROUP\|\.\|\.\|\.]] [\-\-without=GROUP[ GROUP\|\.\|\.\|\.]]
+\fBbundle install\fR [\-\-binstubs[=DIRECTORY]] [\-\-clean] [\-\-deployment] [\-\-frozen] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-no\-cache] [\-\-no\-prune] [\-\-path PATH] [\-\-quiet] [\-\-redownload] [\-\-retry=NUMBER] [\-\-shebang] [\-\-standalone[=GROUP[ GROUP\.\.\.]]] [\-\-system] [\-\-trust\-policy=POLICY] [\-\-with=GROUP[ GROUP\.\.\.]] [\-\-without=GROUP[ GROUP\.\.\.]]
+.
.SH "DESCRIPTION"
Install the gems specified in your Gemfile(5)\. If this is the first time you run bundle install (and a \fBGemfile\.lock\fR does not exist), Bundler will fetch all remote sources, resolve dependencies and install all needed gems\.
+.
.P
If a \fBGemfile\.lock\fR does exist, and you have not updated your Gemfile(5), Bundler will fetch all remote sources, but use the dependencies specified in the \fBGemfile\.lock\fR instead of resolving dependencies\.
+.
.P
If a \fBGemfile\.lock\fR does exist, and you have updated your Gemfile(5), Bundler will use the dependencies in the \fBGemfile\.lock\fR for all gems that you did not update, but will re\-resolve the dependencies of gems that you did update\. You can find more information about this update process below under \fICONSERVATIVE UPDATING\fR\.
+.
.SH "OPTIONS"
The \fB\-\-clean\fR, \fB\-\-deployment\fR, \fB\-\-frozen\fR, \fB\-\-no\-prune\fR, \fB\-\-path\fR, \fB\-\-shebang\fR, \fB\-\-system\fR, \fB\-\-without\fR and \fB\-\-with\fR options are deprecated because they only make sense if they are applied to every subsequent \fBbundle install\fR run automatically and that requires \fBbundler\fR to silently remember them\. Since \fBbundler\fR will no longer remember CLI flags in future versions, \fBbundle config\fR (see bundle\-config(1)) should be used to apply them permanently\.
+.
.TP
\fB\-\-binstubs[=<directory>]\fR
Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it in \fBbin/\fR\. This lets you link the binstub inside of an application to the exact gem version the application needs\.
+.
.IP
-Creates a directory (defaults to \fB~/bin\fR) and places any executables from the gem there\. These executables run in Bundler's context\. If used, you might add this directory to your environment's \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
+Creates a directory (defaults to \fB~/bin\fR) and places any executables from the gem there\. These executables run in Bundler\'s context\. If used, you might add this directory to your environment\'s \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
+.
.TP
\fB\-\-clean\fR
-On finishing the installation Bundler is going to remove any gems not present in the current Gemfile(5)\. Don't worry, gems currently in use will not be removed\.
+On finishing the installation Bundler is going to remove any gems not present in the current Gemfile(5)\. Don\'t worry, gems currently in use will not be removed\.
+.
.IP
This option is deprecated in favor of the \fBclean\fR setting\.
+.
.TP
\fB\-\-deployment\fR
-In \fIdeployment mode\fR, Bundler will 'roll\-out' the bundle for production or CI use\. Please check carefully if you want to have this option enabled in your development environment\.
+In \fIdeployment mode\fR, Bundler will \'roll\-out\' the bundle for production or CI use\. Please check carefully if you want to have this option enabled in your development environment\.
+.
.IP
This option is deprecated in favor of the \fBdeployment\fR setting\.
+.
.TP
\fB\-\-redownload\fR
Force download every gem, even if the required versions are already available locally\.
+.
.TP
\fB\-\-frozen\fR
Do not allow the Gemfile\.lock to be updated after this install\. Exits non\-zero if there are going to be changes to the Gemfile\.lock\.
+.
.IP
This option is deprecated in favor of the \fBfrozen\fR setting\.
+.
.TP
\fB\-\-full\-index\fR
-Bundler will not call Rubygems' API endpoint (default) but download and cache a (currently big) index file of all gems\. Performance can be improved for large bundles that seldom change by enabling this option\.
+Bundler will not call Rubygems\' API endpoint (default) but download and cache a (currently big) index file of all gems\. Performance can be improved for large bundles that seldom change by enabling this option\.
+.
.TP
\fB\-\-gemfile=<gemfile>\fR
-The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\.
+The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project\'s root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\.
+.
.TP
\fB\-\-jobs=[<number>]\fR, \fB\-j[<number>]\fR
The maximum number of parallel download and install jobs\. The default is the number of available processors\.
+.
.TP
\fB\-\-local\fR
-Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
+Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
+.
.TP
\fB\-\-prefer\-local\fR
-Force using locally installed gems, or gems already present in Rubygems' cache or in \fBvendor/cache\fR, when resolving, even if newer versions are available remotely\. Only attempt to connect to \fBrubygems\.org\fR for gems that are not present locally\.
+Force using locally installed gems, or gems already present in Rubygems\' cache or in \fBvendor/cache\fR, when resolving, even if newer versions are available remotely\. Only attempt to connect to \fBrubygems\.org\fR for gems that are not present locally\.
+.
.TP
\fB\-\-no\-cache\fR
Do not update the cache in \fBvendor/cache\fR with the newly bundled gems\. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install\.
+.
.TP
\fB\-\-no\-prune\fR
-Don't remove stale gems from the cache when the installation finishes\.
+Don\'t remove stale gems from the cache when the installation finishes\.
+.
.IP
This option is deprecated in favor of the \fBno_prune\fR setting\.
+.
.TP
\fB\-\-path=<path>\fR
-The location to install the specified gems to\. This defaults to Rubygems' setting\. Bundler shares this location with Rubygems, \fBgem install \|\.\|\.\|\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \|\.\|\.\|\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\.
+The location to install the specified gems to\. This defaults to Rubygems\' setting\. Bundler shares this location with Rubygems, \fBgem install \.\.\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \.\.\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\.
+.
.IP
This option is deprecated in favor of the \fBpath\fR setting\.
+.
.TP
\fB\-\-quiet\fR
Do not print progress information to the standard output\. Instead, Bundler will exit using a status code (\fB$?\fR)\.
+.
.TP
\fB\-\-retry=[<number>]\fR
Retry failed network or git requests for \fInumber\fR times\.
+.
.TP
\fB\-\-shebang=<ruby\-executable>\fR
Uses the specified ruby executable (usually \fBruby\fR) to execute the scripts created with \fB\-\-binstubs\fR\. In addition, if you use \fB\-\-binstubs\fR together with \fB\-\-shebang jruby\fR these executables will be changed to execute \fBjruby\fR instead\.
+.
.IP
This option is deprecated in favor of the \fBshebang\fR setting\.
+.
.TP
\fB\-\-standalone[=<list>]\fR
-Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install has to be specified\. Bundler creates a directory named \fBbundle\fR and installs the bundle there\. It also generates a \fBbundle/bundler/setup\.rb\fR file to replace Bundler's own setup in the manner required\. Using this option implicitly sets \fBpath\fR, which is a [remembered option][REMEMBERED OPTIONS]\.
+Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install has to be specified\. Bundler creates a directory named \fBbundle\fR and installs the bundle there\. It also generates a \fBbundle/bundler/setup\.rb\fR file to replace Bundler\'s own setup in the manner required\. Using this option implicitly sets \fBpath\fR, which is a [remembered option][REMEMBERED OPTIONS]\.
+.
.TP
\fB\-\-system\fR
-Installs the gems specified in the bundle to the system's Rubygems location\. This overrides any previous configuration of \fB\-\-path\fR\.
+Installs the gems specified in the bundle to the system\'s Rubygems location\. This overrides any previous configuration of \fB\-\-path\fR\.
+.
.IP
This option is deprecated in favor of the \fBsystem\fR setting\.
+.
.TP
\fB\-\-trust\-policy=[<policy>]\fR
Apply the Rubygems security policy \fIpolicy\fR, where policy is one of \fBHighSecurity\fR, \fBMediumSecurity\fR, \fBLowSecurity\fR, \fBAlmostNoSecurity\fR, or \fBNoSecurity\fR\. For more details, please see the Rubygems signing documentation linked below in \fISEE ALSO\fR\.
+.
.TP
\fB\-\-with=<list>\fR
A space\-separated list of groups referencing gems to install\. If an optional group is given it is installed\. If a group is given that is in the remembered list of groups given to \-\-without, it is removed from that list\.
+.
.IP
This option is deprecated in favor of the \fBwith\fR setting\.
+.
.TP
\fB\-\-without=<list>\fR
A space\-separated list of groups referencing gems to skip during installation\. If a group is given that is in the remembered list of groups given to \-\-with, it is removed from that list\.
+.
.IP
This option is deprecated in favor of the \fBwithout\fR setting\.
+.
.SH "DEPLOYMENT MODE"
-Bundler's defaults are optimized for development\. To switch to defaults optimized for deployment and for CI, use the \fB\-\-deployment\fR flag\. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified\.
+Bundler\'s defaults are optimized for development\. To switch to defaults optimized for deployment and for CI, use the \fB\-\-deployment\fR flag\. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified\.
+.
.IP "1." 4
A \fBGemfile\.lock\fR is required\.
+.
.IP
To ensure that the same versions of the gems you developed with and tested with are also used in deployments, a \fBGemfile\.lock\fR is required\.
+.
.IP
This is mainly to ensure that you remember to check your \fBGemfile\.lock\fR into version control\.
+.
.IP "2." 4
The \fBGemfile\.lock\fR must be up to date
+.
.IP
In development, you can modify your Gemfile(5) and re\-run \fBbundle install\fR to \fIconservatively update\fR your \fBGemfile\.lock\fR snapshot\.
+.
.IP
In deployment, your \fBGemfile\.lock\fR should be up\-to\-date with changes made in your Gemfile(5)\.
+.
.IP "3." 4
Gems are installed to \fBvendor/bundle\fR not your default system location
+.
.IP
-In development, it's convenient to share the gems used in your application with other applications and other scripts that run on the system\.
+In development, it\'s convenient to share the gems used in your application with other applications and other scripts that run on the system\.
+.
.IP
In deployment, isolation is a more important default\. In addition, the user deploying the application may not have permission to install gems to the system, or the web server may not have permission to read them\.
+.
.IP
As a result, \fBbundle install \-\-deployment\fR installs gems to the \fBvendor/bundle\fR directory in the application\. This may be overridden using the \fB\-\-path\fR option\.
+.
.IP "" 0
+.
.SH "INSTALLING GROUPS"
By default, \fBbundle install\fR will install all gems in all groups in your Gemfile(5), except those declared for a different platform\.
+.
.P
However, you can explicitly tell Bundler to skip installing certain groups with the \fB\-\-without\fR option\. This option takes a space\-separated list of groups\.
+.
.P
While the \fB\-\-without\fR option will skip \fIinstalling\fR the gems in the specified groups, it will still \fIdownload\fR those gems and use them to resolve the dependencies of every gem in your Gemfile(5)\.
+.
.P
This is so that installing a different set of groups on another machine (such as a production server) will not change the gems and versions that you have already developed and tested against\.
+.
.P
\fBBundler offers a rock\-solid guarantee that the third\-party code you are running in development and testing is also the third\-party code you are running in production\. You can choose to exclude some of that code in different environments, but you will never be caught flat\-footed by different versions of third\-party code being used in different environments\.\fR
+.
.P
For a simple illustration, consider the following Gemfile(5):
+.
.IP "" 4
+.
.nf
-source 'https://rubygems\.org'
-gem 'sinatra'
+source \'https://rubygems\.org\'
+
+gem \'sinatra\'
group :production do
- gem 'rack\-perftools\-profiler'
+ gem \'rack\-perftools\-profiler\'
end
+.
.fi
+.
.IP "" 0
+.
.P
In this case, \fBsinatra\fR depends on any version of Rack (\fB>= 1\.0\fR), while \fBrack\-perftools\-profiler\fR depends on 1\.x (\fB~> 1\.0\fR)\.
+.
.P
When you run \fBbundle install \-\-without production\fR in development, we look at the dependencies of \fBrack\-perftools\-profiler\fR as well\. That way, you do not spend all your time developing against Rack 2\.0, using new APIs unavailable in Rack 1\.x, only to have Bundler switch to Rack 1\.2 when the \fBproduction\fR group \fIis\fR used\.
+.
.P
This should not cause any problems in practice, because we do not attempt to \fBinstall\fR the gems in the excluded groups, and only evaluate as part of the dependency resolution process\.
+.
.P
This also means that you cannot include different versions of the same gem in different groups, because doing so would result in different sets of dependencies used in development and production\. Because of the vagaries of the dependency resolution process, this usually affects more than the gems you list in your Gemfile(5), and can (surprisingly) radically change the gems you are using\.
+.
.SH "THE GEMFILE\.LOCK"
When you run \fBbundle install\fR, Bundler will persist the full names and versions of all gems that you used (including dependencies of the gems specified in the Gemfile(5)) into a file called \fBGemfile\.lock\fR\.
+.
.P
Bundler uses this file in all subsequent calls to \fBbundle install\fR, which guarantees that you always use the same exact code, even as your application moves across machines\.
+.
.P
Because of the way dependency resolution works, even a seemingly small change (for instance, an update to a point\-release of a dependency of a gem in your Gemfile(5)) can result in radically different gems being needed to satisfy all dependencies\.
+.
.P
As a result, you \fBSHOULD\fR check your \fBGemfile\.lock\fR into version control, in both applications and gems\. If you do not, every machine that checks out your repository (including your production server) will resolve all dependencies again, which will result in different versions of third\-party code being used if \fBany\fR of the gems in the Gemfile(5) or any of their dependencies have been updated\.
+.
.P
When Bundler first shipped, the \fBGemfile\.lock\fR was included in the \fB\.gitignore\fR file included with generated gems\. Over time, however, it became clear that this practice forces the pain of broken dependencies onto new contributors, while leaving existing contributors potentially unaware of the problem\. Since \fBbundle install\fR is usually the first step towards a contribution, the pain of broken dependencies would discourage new contributors from contributing\. As a result, we have revised our guidance for gem authors to now recommend checking in the lock for gems\.
+.
.SH "CONSERVATIVE UPDATING"
When you make a change to the Gemfile(5) and then run \fBbundle install\fR, Bundler will update only the gems that you modified\.
+.
.P
In other words, if a gem that you \fBdid not modify\fR worked before you called \fBbundle install\fR, it will continue to use the exact same versions of all dependencies as it used before the update\.
+.
.P
-Let's take a look at an example\. Here's your original Gemfile(5):
+Let\'s take a look at an example\. Here\'s your original Gemfile(5):
+.
.IP "" 4
+.
.nf
-source 'https://rubygems\.org'
-gem 'actionpack', '2\.3\.8'
-gem 'activemerchant'
+source \'https://rubygems\.org\'
+
+gem \'actionpack\', \'2\.3\.8\'
+gem \'activemerchant\'
+.
.fi
+.
.IP "" 0
+.
.P
In this case, both \fBactionpack\fR and \fBactivemerchant\fR depend on \fBactivesupport\fR\. The \fBactionpack\fR gem depends on \fBactivesupport 2\.3\.8\fR and \fBrack ~> 1\.1\.0\fR, while the \fBactivemerchant\fR gem depends on \fBactivesupport >= 2\.3\.2\fR, \fBbraintree >= 2\.0\.0\fR, and \fBbuilder >= 2\.0\.0\fR\.
+.
.P
When the dependencies are first resolved, Bundler will select \fBactivesupport 2\.3\.8\fR, which satisfies the requirements of both gems in your Gemfile(5)\.
+.
.P
Next, you modify your Gemfile(5) to:
+.
.IP "" 4
+.
.nf
-source 'https://rubygems\.org'
-gem 'actionpack', '3\.0\.0\.rc'
-gem 'activemerchant'
+source \'https://rubygems\.org\'
+
+gem \'actionpack\', \'3\.0\.0\.rc\'
+gem \'activemerchant\'
+.
.fi
+.
.IP "" 0
+.
.P
The \fBactionpack 3\.0\.0\.rc\fR gem has a number of new dependencies, and updates the \fBactivesupport\fR dependency to \fB= 3\.0\.0\.rc\fR and the \fBrack\fR dependency to \fB~> 1\.2\.1\fR\.
+.
.P
When you run \fBbundle install\fR, Bundler notices that you changed the \fBactionpack\fR gem, but not the \fBactivemerchant\fR gem\. It evaluates the gems currently being used to satisfy its requirements:
+.
.TP
\fBactivesupport 2\.3\.8\fR
also used to satisfy a dependency in \fBactivemerchant\fR, which is not being updated
+.
.TP
\fBrack ~> 1\.1\.0\fR
not currently being used to satisfy another dependency
+.
.P
Because you did not explicitly ask to update \fBactivemerchant\fR, you would not expect it to suddenly stop working after updating \fBactionpack\fR\. However, satisfying the new \fBactivesupport 3\.0\.0\.rc\fR dependency of actionpack requires updating one of its dependencies\.
+.
.P
Even though \fBactivemerchant\fR declares a very loose dependency that theoretically matches \fBactivesupport 3\.0\.0\.rc\fR, Bundler treats gems in your Gemfile(5) that have not changed as an atomic unit together with their dependencies\. In this case, the \fBactivemerchant\fR dependency is treated as \fBactivemerchant 1\.7\.1 + activesupport 2\.3\.8\fR, so \fBbundle install\fR will report that it cannot update \fBactionpack\fR\.
+.
.P
To explicitly update \fBactionpack\fR, including its dependencies which other gems in the Gemfile(5) still depend on, run \fBbundle update actionpack\fR (see \fBbundle update(1)\fR)\.
+.
.P
\fBSummary\fR: In general, after making a change to the Gemfile(5) , you should first try to run \fBbundle install\fR, which will guarantee that no other gem in the Gemfile(5) is impacted by the change\. If that does not work, run bundle update(1) \fIbundle\-update\.1\.html\fR\.
+.
.SH "SEE ALSO"
+.
.IP "\(bu" 4
-Gem install docs \fIhttps://guides\.rubygems\.org/rubygems\-basics/#installing\-gems\fR
+Gem install docs \fIhttp://guides\.rubygems\.org/rubygems\-basics/#installing\-gems\fR
+.
.IP "\(bu" 4
-Rubygems signing docs \fIhttps://guides\.rubygems\.org/security/\fR
+Rubygems signing docs \fIhttp://guides\.rubygems\.org/security/\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-install.1.ronn b/lib/bundler/man/bundle-install.1.ronn
index ed8169de05..be9ed0f974 100644
--- a/lib/bundler/man/bundle-install.1.ronn
+++ b/lib/bundler/man/bundle-install.1.ronn
@@ -14,7 +14,6 @@ bundle-install(1) -- Install the dependencies specified in your Gemfile
[--no-cache]
[--no-prune]
[--path PATH]
- [--prefer-local]
[--quiet]
[--redownload]
[--retry=NUMBER]
@@ -379,5 +378,5 @@ does not work, run [bundle update(1)](bundle-update.1.html).
## SEE ALSO
-* [Gem install docs](https://guides.rubygems.org/rubygems-basics/#installing-gems)
-* [Rubygems signing docs](https://guides.rubygems.org/security/)
+* [Gem install docs](http://guides.rubygems.org/rubygems-basics/#installing-gems)
+* [Rubygems signing docs](http://guides.rubygems.org/security/)
diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1
index 5cbb1c3cfe..37d2c837e4 100644
--- a/lib/bundler/man/bundle-list.1
+++ b/lib/bundler/man/bundle-list.1
@@ -1,34 +1,49 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-LIST" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-LIST" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-list\fR \- List all the gems in the bundle
+.
.SH "SYNOPSIS"
-\fBbundle list\fR [\-\-name\-only] [\-\-paths] [\-\-without\-group=GROUP[ GROUP\|\.\|\.\|\.]] [\-\-only\-group=GROUP[ GROUP\|\.\|\.\|\.]]
+\fBbundle list\fR [\-\-name\-only] [\-\-paths] [\-\-without\-group=GROUP[ GROUP\.\.\.]] [\-\-only\-group=GROUP[ GROUP\.\.\.]]
+.
.SH "DESCRIPTION"
Prints a list of all the gems in the bundle including their version\.
+.
.P
Example:
+.
.P
bundle list \-\-name\-only
+.
.P
bundle list \-\-paths
+.
.P
bundle list \-\-without\-group test
+.
.P
bundle list \-\-only\-group dev
+.
.P
bundle list \-\-only\-group dev test \-\-paths
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-name\-only\fR
Print only the name of each gem\.
+.
.TP
\fB\-\-paths\fR
Print the path to each gem in the bundle\.
+.
.TP
\fB\-\-without\-group=<list>\fR
A space\-separated list of groups of gems to skip during printing\.
+.
.TP
\fB\-\-only\-group=<list>\fR
A space\-separated list of groups of gems to print\.
diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1
index 5f0d43a9aa..422da46d00 100644
--- a/lib/bundler/man/bundle-lock.1
+++ b/lib/bundler/man/bundle-lock.1
@@ -1,60 +1,84 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-LOCK" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-LOCK" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-lock\fR \- Creates / Updates a lockfile without installing
+.
.SH "SYNOPSIS"
\fBbundle lock\fR [\-\-update] [\-\-local] [\-\-print] [\-\-lockfile=PATH] [\-\-full\-index] [\-\-add\-platform] [\-\-remove\-platform] [\-\-patch] [\-\-minor] [\-\-major] [\-\-strict] [\-\-conservative]
+.
.SH "DESCRIPTION"
Lock the gems specified in Gemfile\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-update=<*gems>\fR
Ignores the existing lockfile\. Resolve then updates lockfile\. Taking a list of gems or updating all gems if no list is given\.
+.
.TP
\fB\-\-local\fR
-Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
+Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
+.
.TP
\fB\-\-print\fR
Prints the lockfile to STDOUT instead of writing to the file system\.
+.
.TP
\fB\-\-lockfile=<path>\fR
The path where the lockfile should be written to\.
+.
.TP
\fB\-\-full\-index\fR
Fall back to using the single\-file index of all gems\.
+.
.TP
\fB\-\-add\-platform\fR
Add a new platform to the lockfile, re\-resolving for the addition of that platform\.
+.
.TP
\fB\-\-remove\-platform\fR
Remove a platform from the lockfile\.
+.
.TP
\fB\-\-patch\fR
If updating, prefer updating only to next patch version\.
+.
.TP
\fB\-\-minor\fR
If updating, prefer updating only to next minor version\.
+.
.TP
\fB\-\-major\fR
If updating, prefer updating to next major version (default)\.
+.
.TP
\fB\-\-strict\fR
If updating, do not allow any gem to be updated past latest \-\-patch | \-\-minor | \-\-major\.
+.
.TP
\fB\-\-conservative\fR
If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated\.
+.
.SH "UPDATING ALL GEMS"
If you run \fBbundle lock\fR with \fB\-\-update\fR option without list of gems, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\.
+.
.SH "UPDATING A LIST OF GEMS"
Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\.
+.
.P
For instance, you only want to update \fBnokogiri\fR, run \fBbundle lock \-\-update nokogiri\fR\.
+.
.P
Bundler will update \fBnokogiri\fR and any of its dependencies, but leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\.
+.
.SH "SUPPORTING OTHER PLATFORMS"
-If you want your bundle to support platforms other than the one you're running locally, you can run \fBbundle lock \-\-add\-platform PLATFORM\fR to add PLATFORM to the lockfile, force bundler to re\-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform\-specific gems on\.
+If you want your bundle to support platforms other than the one you\'re running locally, you can run \fBbundle lock \-\-add\-platform PLATFORM\fR to add PLATFORM to the lockfile, force bundler to re\-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform\-specific gems on\.
+.
.P
For a full explanation of gem platforms, see \fBgem help platform\fR\.
+.
.SH "PATCH LEVEL OPTIONS"
See bundle update(1) \fIbundle\-update\.1\.html\fR for details\.
diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1
index fb5ff1fee7..c831bf9ce9 100644
--- a/lib/bundler/man/bundle-open.1
+++ b/lib/bundler/man/bundle-open.1
@@ -1,31 +1,51 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-OPEN" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-OPEN" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-open\fR \- Opens the source directory for a gem in your bundle
+.
.SH "SYNOPSIS"
\fBbundle open\fR [GEM] [\-\-path=PATH]
+.
.SH "DESCRIPTION"
Opens the source directory of the provided GEM in your editor\.
+.
.P
For this to work the \fBEDITOR\fR or \fBBUNDLER_EDITOR\fR environment variable has to be set\.
+.
.P
Example:
+.
.IP "" 4
+.
.nf
-bundle open 'rack'
+
+bundle open \'rack\'
+.
.fi
+.
.IP "" 0
+.
.P
-Will open the source directory for the 'rack' gem in your bundle\.
+Will open the source directory for the \'rack\' gem in your bundle\.
+.
.IP "" 4
+.
.nf
-bundle open 'rack' \-\-path 'README\.md'
+
+bundle open \'rack\' \-\-path \'README\.md\'
+.
.fi
+.
.IP "" 0
+.
.P
-Will open the README\.md file of the 'rack' gem source in your bundle\.
+Will open the README\.md file of the \'rack\' gem source in your bundle\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-path\fR
Specify GEM source relative path to open\.
diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1
index ea3005dd87..40fe8a4def 100644
--- a/lib/bundler/man/bundle-outdated.1
+++ b/lib/bundler/man/bundle-outdated.1
@@ -1,100 +1,148 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-OUTDATED" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-OUTDATED" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-outdated\fR \- List installed gems with newer versions available
+.
.SH "SYNOPSIS"
\fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit]
+.
.SH "DESCRIPTION"
Outdated lists the names and versions of gems that have a newer version available in the given source\. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems\. Prerelease gems are ignored by default\. If your gems are up to date, Bundler will exit with a status of 0\. Otherwise, it will exit 1\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-local\fR
Do not attempt to fetch gems remotely and use the gem cache instead\.
+.
.TP
\fB\-\-pre\fR
Check for newer pre\-release gems\.
+.
.TP
\fB\-\-source\fR
Check against a specific source\.
+.
.TP
\fB\-\-strict\fR
Only list newer versions allowed by your Gemfile requirements, also respecting conservative update flags (\-\-patch, \-\-minor, \-\-major)\.
+.
.TP
\fB\-\-parseable\fR, \fB\-\-porcelain\fR
Use minimal formatting for more parseable output\.
+.
.TP
\fB\-\-group\fR
List gems from a specific group\.
+.
.TP
\fB\-\-groups\fR
List gems organized by groups\.
+.
.TP
\fB\-\-minor\fR
Prefer updating only to next minor version\.
+.
.TP
\fB\-\-major\fR
Prefer updating to next major version (default)\.
+.
.TP
\fB\-\-patch\fR
Prefer updating only to next patch version\.
+.
.TP
\fB\-\-filter\-major\fR
Only list major newer versions\.
+.
.TP
\fB\-\-filter\-minor\fR
Only list minor newer versions\.
+.
.TP
\fB\-\-filter\-patch\fR
Only list patch newer versions\.
+.
.TP
\fB\-\-only\-explicit\fR
Only list gems specified in your Gemfile, not their dependencies\.
+.
.SH "PATCH LEVEL OPTIONS"
See bundle update(1) \fIbundle\-update\.1\.html\fR for details\.
+.
.SH "FILTERING OUTPUT"
The 3 filtering options do not affect the resolution of versions, merely what versions are shown in the output\.
+.
.P
If the regular output shows the following:
+.
.IP "" 4
+.
.nf
-* Gem Current Latest Requested Groups
-* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test
-* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default
-* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test
+
+* faker (newest 1\.6\.6, installed 1\.6\.5, requested ~> 1\.4) in groups "development, test"
+* hashie (newest 3\.4\.6, installed 1\.2\.0, requested = 1\.2\.0) in groups "default"
+* headless (newest 2\.3\.1, installed 2\.2\.3) in groups "test"
+.
.fi
+.
.IP "" 0
+.
.P
\fB\-\-filter\-major\fR would only show:
+.
.IP "" 4
+.
.nf
-* Gem Current Latest Requested Groups
-* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default
+
+* hashie (newest 3\.4\.6, installed 1\.2\.0, requested = 1\.2\.0) in groups "default"
+.
.fi
+.
.IP "" 0
+.
.P
\fB\-\-filter\-minor\fR would only show:
+.
.IP "" 4
+.
.nf
-* Gem Current Latest Requested Groups
-* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test
+
+* headless (newest 2\.3\.1, installed 2\.2\.3) in groups "test"
+.
.fi
+.
.IP "" 0
+.
.P
\fB\-\-filter\-patch\fR would only show:
+.
.IP "" 4
+.
.nf
-* Gem Current Latest Requested Groups
-* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test
+
+* faker (newest 1\.6\.6, installed 1\.6\.5, requested ~> 1\.4) in groups "development, test"
+.
.fi
+.
.IP "" 0
+.
.P
Filter options can be combined\. \fB\-\-filter\-minor\fR and \fB\-\-filter\-patch\fR would show:
+.
.IP "" 4
+.
.nf
-* Gem Current Latest Requested Groups
-* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test
+
+* faker (newest 1\.6\.6, installed 1\.6\.5, requested ~> 1\.4) in groups "development, test"
+* headless (newest 2\.3\.1, installed 2\.2\.3) in groups "test"
+.
.fi
+.
.IP "" 0
+.
.P
Combining all three \fBfilter\fR options would be the same result as providing none of them\.
diff --git a/lib/bundler/man/bundle-outdated.1.ronn b/lib/bundler/man/bundle-outdated.1.ronn
index 4ac65d0532..04096ffbb6 100644
--- a/lib/bundler/man/bundle-outdated.1.ronn
+++ b/lib/bundler/man/bundle-outdated.1.ronn
@@ -78,29 +78,25 @@ in the output.
If the regular output shows the following:
- * Gem Current Latest Requested Groups
- * faker 1.6.5 1.6.6 ~> 1.4 development, test
- * hashie 1.2.0 3.4.6 = 1.2.0 default
- * headless 2.2.3 2.3.1 = 2.2.3 test
+ * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test"
+ * hashie (newest 3.4.6, installed 1.2.0, requested = 1.2.0) in groups "default"
+ * headless (newest 2.3.1, installed 2.2.3) in groups "test"
`--filter-major` would only show:
- * Gem Current Latest Requested Groups
- * hashie 1.2.0 3.4.6 = 1.2.0 default
+ * hashie (newest 3.4.6, installed 1.2.0, requested = 1.2.0) in groups "default"
`--filter-minor` would only show:
- * Gem Current Latest Requested Groups
- * headless 2.2.3 2.3.1 = 2.2.3 test
+ * headless (newest 2.3.1, installed 2.2.3) in groups "test"
`--filter-patch` would only show:
- * Gem Current Latest Requested Groups
- * faker 1.6.5 1.6.6 ~> 1.4 development, test
+ * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test"
Filter options can be combined. `--filter-minor` and `--filter-patch` would show:
- * Gem Current Latest Requested Groups
- * faker 1.6.5 1.6.6 ~> 1.4 development, test
+ * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test"
+ * headless (newest 2.3.1, installed 2.2.3) in groups "test"
Combining all three `filter` options would be the same result as providing none of them.
diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1
index c3058175fc..d0015a80ef 100644
--- a/lib/bundler/man/bundle-platform.1
+++ b/lib/bundler/man/bundle-platform.1
@@ -1,27 +1,41 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-PLATFORM" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-PLATFORM" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-platform\fR \- Displays platform compatibility information
+.
.SH "SYNOPSIS"
\fBbundle platform\fR [\-\-ruby]
+.
.SH "DESCRIPTION"
\fBplatform\fR displays information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\.
+.
.P
For instance, using this Gemfile(5):
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
ruby "3\.1\.2"
gem "rack"
+.
.fi
+.
.IP "" 0
+.
.P
If you run \fBbundle platform\fR on Ruby 3\.1\.2, it displays the following output:
+.
.IP "" 4
+.
.nf
+
Your platform is: x86_64\-linux
Your app has gems that work on these platforms:
@@ -34,16 +48,24 @@ Your Gemfile specifies a Ruby version requirement:
* ruby 3\.1\.2
Your current platform satisfies the Ruby version requirement\.
+.
.fi
+.
.IP "" 0
+.
.P
-\fBplatform\fR lists all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It also lets you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn't match the running Ruby VM, it tells you what part does not\.
+\fBplatform\fR lists all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It also lets you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn\'t match the running Ruby VM, it tells you what part does not\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-ruby\fR
-It will display the ruby directive information, so you don't have to parse it from the Gemfile(5)\.
+It will display the ruby directive information, so you don\'t have to parse it from the Gemfile(5)\.
+.
.SH "SEE ALSO"
+.
.IP "\(bu" 4
bundle\-lock(1) \fIbundle\-lock\.1\.html\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1
index 34437d9973..a231bb1e3d 100644
--- a/lib/bundler/man/bundle-plugin.1
+++ b/lib/bundler/man/bundle-plugin.1
@@ -1,58 +1,81 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-PLUGIN" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-PLUGIN" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-plugin\fR \- Manage Bundler plugins
+.
.SH "SYNOPSIS"
-\fBbundle plugin\fR install PLUGINS [\-\-source=\fISOURCE\fR] [\-\-version=\fIversion\fR] [\-\-git=\fIgit\-url\fR] [\-\-branch=\fIbranch\fR|\-\-ref=\fIrev\fR] [\-\-path=\fIpath\fR]
+\fBbundle plugin\fR install PLUGINS [\-\-source=\fISOURCE\fR] [\-\-version=\fIversion\fR] [\-\-git|\-\-local_git=\fIgit\-url\fR] [\-\-branch=\fIbranch\fR|\-\-ref=\fIrev\fR]
+.
.br
\fBbundle plugin\fR uninstall PLUGINS
+.
.br
\fBbundle plugin\fR list
+.
.br
\fBbundle plugin\fR help [COMMAND]
+.
.SH "DESCRIPTION"
You can install, uninstall, and list plugin(s) with this command to extend functionalities of Bundler\.
+.
.SH "SUB\-COMMANDS"
+.
.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\.
-.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\.
-.TP
-\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\. You can use standard Git URLs like:
-.IP
+.
+.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\.
+.
+.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\.
+.
+.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\.
+.
+.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 "\(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, you can use \fB\-\-branch\fR or \fB\-\-ref\fR to specify any branch, tag, or commit hash (revision) to use\.
-.TP
-\fBbundle plugin install bundler\-graph \-\-path \.\./bundler\-graph\fR
-Install bundler\-graph gem from a local path\.
+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\.
+.
.SS "list"
List the installed plugins and available commands\.
+.
.P
No options\.
+.
.SS "help"
Describe subcommands or one specific subcommand\.
+.
.P
No options\.
+.
.SH "SEE ALSO"
+.
.IP "\(bu" 4
How to write a Bundler plugin \fIhttps://bundler\.io/guides/bundler_plugins\.html\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-plugin.1.ronn b/lib/bundler/man/bundle-plugin.1.ronn
index b0a34660ea..4f234eeba7 100644
--- a/lib/bundler/man/bundle-plugin.1.ronn
+++ b/lib/bundler/man/bundle-plugin.1.ronn
@@ -4,8 +4,7 @@ bundle-plugin(1) -- Manage Bundler plugins
## SYNOPSIS
`bundle plugin` install PLUGINS [--source=<SOURCE>] [--version=<version>]
- [--git=<git-url>] [--branch=<branch>|--ref=<rev>]
- [--path=<path>]<br>
+ [--git|--local_git=<git-url>] [--branch=<branch>|--ref=<rev>]<br>
`bundle plugin` uninstall PLUGINS<br>
`bundle plugin` list<br>
`bundle plugin` help [COMMAND]
@@ -21,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.
@@ -30,17 +29,14 @@ Install the given plugin(s).
You can specify the version of the gem via `--version`.
* `bundle plugin install bundler-graph --git https://github.com/rubygems/bundler-graph`:
- Install bundler-graph gem from Git repository. You can use standard Git URLs like:
+ 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`, you can use `--branch` or `--ref` to specify any branch, tag, or commit hash (revision) to use.
-
-* `bundle plugin install bundler-graph --path ../bundler-graph`:
- Install bundler-graph gem from a local path.
+ 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.
### uninstall
diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1
index 103c6f68ae..8f4bad3db6 100644
--- a/lib/bundler/man/bundle-pristine.1
+++ b/lib/bundler/man/bundle-pristine.1
@@ -1,23 +1,34 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-PRISTINE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-PRISTINE" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-pristine\fR \- Restores installed gems to their pristine condition
+.
.SH "SYNOPSIS"
\fBbundle pristine\fR
+.
.SH "DESCRIPTION"
\fBpristine\fR restores the installed gems in the bundle to their pristine condition using the local gem cache from RubyGems\. For git gems, a forced checkout will be performed\.
+.
.P
-For further explanation, \fBbundle pristine\fR ignores unpacked files on disk\. In other words, this command utilizes the local \fB\.gem\fR cache or the gem's git repository as if one were installing from scratch\.
+For further explanation, \fBbundle pristine\fR ignores unpacked files on disk\. In other words, this command utilizes the local \fB\.gem\fR cache or the gem\'s git repository as if one were installing from scratch\.
+.
.P
-Note: the Bundler gem cannot be restored to its original state with \fBpristine\fR\. One also cannot use \fBbundle pristine\fR on gems with a 'path' option in the Gemfile, because bundler has no original copy it can restore from\.
+Note: the Bundler gem cannot be restored to its original state with \fBpristine\fR\. One also cannot use \fBbundle pristine\fR on gems with a \'path\' option in the Gemfile, because bundler has no original copy it can restore from\.
+.
.P
When is it practical to use \fBbundle pristine\fR?
+.
.P
It comes in handy when a developer is debugging a gem\. \fBbundle pristine\fR is a great way to get rid of experimental changes to a gem that one may not want\.
+.
.P
Why use \fBbundle pristine\fR over \fBgem pristine \-\-all\fR?
+.
.P
Both commands are very similar\. For context: \fBbundle pristine\fR, without arguments, cleans all gems from the lockfile\. Meanwhile, \fBgem pristine \-\-all\fR cleans all installed gems for that Ruby version\.
+.
.P
If a developer forgets which gems in their project they might have been debugging, the Rubygems \fBgem pristine [GEMNAME]\fR command may be inconvenient\. One can avoid waiting for \fBgem pristine \-\-all\fR, and instead run \fBbundle pristine\fR\.
diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1
index 4a2ed4eb13..97a65016ac 100644
--- a/lib/bundler/man/bundle-remove.1
+++ b/lib/bundler/man/bundle-remove.1
@@ -1,21 +1,31 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-REMOVE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-REMOVE" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-remove\fR \- Removes gems from the Gemfile
+.
.SH "SYNOPSIS"
-\fBbundle remove [GEM [GEM \|\.\|\.\|\.]] [\-\-install]\fR
+\fBbundle remove [GEM [GEM \.\.\.]] [\-\-install]\fR
+.
.SH "DESCRIPTION"
Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid\. If a gem cannot be removed, a warning is printed\. If a gem is already absent from the Gemfile, and error is raised\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-install\fR
Runs \fBbundle install\fR after the given gems have been removed from the Gemfile, which ensures that both the lockfile and the installed gems on disk are also updated to remove the given gem(s)\.
+.
.P
Example:
+.
.P
bundle remove rails
+.
.P
bundle remove rails rack
+.
.P
bundle remove rails rack \-\-install
diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1
index dfbb439218..82706d45f3 100644
--- a/lib/bundler/man/bundle-show.1
+++ b/lib/bundler/man/bundle-show.1
@@ -1,15 +1,22 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-SHOW" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-SHOW" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem
+.
.SH "SYNOPSIS"
\fBbundle show\fR [GEM] [\-\-paths]
+.
.SH "DESCRIPTION"
Without the [GEM] option, \fBshow\fR will print a list of the names and versions of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by name\.
+.
.P
Calling show with [GEM] will list the exact location of that gem on your machine\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-paths\fR
List the paths of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by gem name\.
diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1
index 5eb9514f03..65448f4806 100644
--- a/lib/bundler/man/bundle-update.1
+++ b/lib/bundler/man/bundle-update.1
@@ -1,81 +1,114 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-UPDATE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-UPDATE" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-update\fR \- Update your gems to the latest available versions
+.
.SH "SYNOPSIS"
\fBbundle update\fR \fI*gems\fR [\-\-all] [\-\-group=NAME] [\-\-source=NAME] [\-\-local] [\-\-ruby] [\-\-bundler[=VERSION]] [\-\-full\-index] [\-\-jobs=JOBS] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-redownload] [\-\-strict] [\-\-conservative]
+.
.SH "DESCRIPTION"
Update the gems specified (all gems, if \fB\-\-all\fR flag is used), ignoring the previously installed gems specified in the \fBGemfile\.lock\fR\. In general, you should use bundle install(1) \fIbundle\-install\.1\.html\fR to install the same exact gems and versions across machines\.
+.
.P
You would use \fBbundle update\fR to explicitly update the version of a gem\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-all\fR
Update all gems specified in Gemfile\.
+.
.TP
\fB\-\-group=<name>\fR, \fB\-g=[<name>]\fR
Only update the gems in the specified group\. For instance, you can update all gems in the development group with \fBbundle update \-\-group development\fR\. You can also call \fBbundle update rails \-\-group test\fR to update the rails gem and all gems in the test group, for example\.
+.
.TP
\fB\-\-source=<name>\fR
The name of a \fB:git\fR or \fB:path\fR source used in the Gemfile(5)\. For instance, with a \fB:git\fR source of \fBhttp://github\.com/rails/rails\.git\fR, you would call \fBbundle update \-\-source rails\fR
+.
.TP
\fB\-\-local\fR
Do not attempt to fetch gems remotely and use the gem cache instead\.
+.
.TP
\fB\-\-ruby\fR
Update the locked version of Ruby to the current version of Ruby\.
+.
.TP
\fB\-\-bundler\fR
Update the locked version of bundler to the invoked bundler version\.
+.
.TP
\fB\-\-full\-index\fR
Fall back to using the single\-file index of all gems\.
+.
.TP
\fB\-\-jobs=[<number>]\fR, \fB\-j[<number>]\fR
Specify the number of jobs to run in parallel\. The default is the number of available processors\.
+.
.TP
\fB\-\-retry=[<number>]\fR
Retry failed network or git requests for \fInumber\fR times\.
+.
.TP
\fB\-\-quiet\fR
Only output warnings and errors\.
+.
.TP
\fB\-\-redownload\fR
Force downloading every gem\.
+.
.TP
\fB\-\-patch\fR
Prefer updating only to next patch version\.
+.
.TP
\fB\-\-minor\fR
Prefer updating only to next minor version\.
+.
.TP
\fB\-\-major\fR
Prefer updating to next major version (default)\.
+.
.TP
\fB\-\-strict\fR
Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\.
+.
.TP
\fB\-\-conservative\fR
Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\.
+.
.SH "UPDATING ALL GEMS"
If you run \fBbundle update \-\-all\fR, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\.
+.
.P
Consider the following Gemfile(5):
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
gem "rails", "3\.0\.0\.rc"
gem "nokogiri"
+.
.fi
+.
.IP "" 0
+.
.P
When you run bundle install(1) \fIbundle\-install\.1\.html\fR the first time, bundler will resolve all of the dependencies, all the way down, and install what you need:
+.
.IP "" 4
+.
.nf
-Fetching gem metadata from https://rubygems\.org/\|\.\|\.\|\.\|\.\|\.\|\.\|\.\|\.\|\.
-Resolving dependencies\|\.\|\.\|\.
+
+Fetching gem metadata from https://rubygems\.org/\.\.\.\.\.\.\.\.\.
+Resolving dependencies\.\.\.
Installing builder 2\.1\.2
Installing abstract 1\.0\.0
Installing rack 1\.2\.8
@@ -105,36 +138,55 @@ Installing nokogiri 1\.6\.5
Bundle complete! 2 Gemfile dependencies, 26 gems total\.
Use `bundle show [gemname]` to see where a bundled gem is installed\.
+.
.fi
+.
.IP "" 0
+.
.P
As you can see, even though you have two gems in the Gemfile(5), your application needs 26 different gems in order to run\. Bundler remembers the exact versions it installed in \fBGemfile\.lock\fR\. The next time you run bundle install(1) \fIbundle\-install\.1\.html\fR, bundler skips the dependency resolution and installs the same gems as it installed last time\.
+.
.P
-After checking in the \fBGemfile\.lock\fR into version control and cloning it on another machine, running bundle install(1) \fIbundle\-install\.1\.html\fR will \fIstill\fR install the gems that you installed last time\. You don't need to worry that a new release of \fBerubis\fR or \fBmail\fR changes the gems you use\.
+After checking in the \fBGemfile\.lock\fR into version control and cloning it on another machine, running bundle install(1) \fIbundle\-install\.1\.html\fR will \fIstill\fR install the gems that you installed last time\. You don\'t need to worry that a new release of \fBerubis\fR or \fBmail\fR changes the gems you use\.
+.
.P
However, from time to time, you might want to update the gems you are using to the newest versions that still match the gems in your Gemfile(5)\.
+.
.P
To do this, run \fBbundle update \-\-all\fR, which will ignore the \fBGemfile\.lock\fR, and resolve all the dependencies again\. Keep in mind that this process can result in a significantly different set of the 25 gems, based on the requirements of new gems that the gem authors released since the last time you ran \fBbundle update \-\-all\fR\.
+.
.SH "UPDATING A LIST OF GEMS"
Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\.
+.
.P
For instance, in the scenario above, imagine that \fBnokogiri\fR releases version \fB1\.4\.4\fR, and you want to update it \fIwithout\fR updating Rails and all of its dependencies\. To do this, run \fBbundle update nokogiri\fR\.
+.
.P
Bundler will update \fBnokogiri\fR and any of its dependencies, but leave alone Rails and its dependencies\.
+.
.SH "OVERLAPPING DEPENDENCIES"
Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same second\-level dependency\. For instance, consider the case of \fBthin\fR and \fBrack\-perftools\-profiler\fR\.
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
gem "thin"
gem "rack\-perftools\-profiler"
+.
.fi
+.
.IP "" 0
+.
.P
The \fBthin\fR gem depends on \fBrack >= 1\.0\fR, while \fBrack\-perftools\-profiler\fR depends on \fBrack ~> 1\.0\fR\. If you run bundle install, you get:
+.
.IP "" 4
+.
.nf
+
Fetching source index for https://rubygems\.org/
Installing daemons (1\.1\.0)
Installing eventmachine (0\.12\.10) with native extensions
@@ -144,132 +196,199 @@ Installing rack (1\.2\.1)
Installing rack\-perftools_profiler (0\.0\.2)
Installing thin (1\.2\.7) with native extensions
Using bundler (1\.0\.0\.rc\.3)
+.
.fi
+.
.IP "" 0
+.
.P
-In this case, the two gems have their own set of dependencies, but they share \fBrack\fR in common\. If you run \fBbundle update thin\fR, bundler will update \fBdaemons\fR, \fBeventmachine\fR and \fBrack\fR, which are dependencies of \fBthin\fR, but not \fBopen4\fR or \fBperftools\.rb\fR, which are dependencies of \fBrack\-perftools_profiler\fR\. Note that \fBbundle update thin\fR will update \fBrack\fR even though it's \fIalso\fR a dependency of \fBrack\-perftools_profiler\fR\.
+In this case, the two gems have their own set of dependencies, but they share \fBrack\fR in common\. If you run \fBbundle update thin\fR, bundler will update \fBdaemons\fR, \fBeventmachine\fR and \fBrack\fR, which are dependencies of \fBthin\fR, but not \fBopen4\fR or \fBperftools\.rb\fR, which are dependencies of \fBrack\-perftools_profiler\fR\. Note that \fBbundle update thin\fR will update \fBrack\fR even though it\'s \fIalso\fR a dependency of \fBrack\-perftools_profiler\fR\.
+.
.P
In short, by default, when you update a gem using \fBbundle update\fR, bundler will update all dependencies of that gem, including those that are also dependencies of another gem\.
+.
.P
To prevent updating indirect dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR:
+.
.P
In this scenario, updating the \fBthin\fR version manually in the Gemfile(5), and then running bundle install(1) \fIbundle\-install\.1\.html\fR will only update \fBdaemons\fR and \fBeventmachine\fR, but not \fBrack\fR\. For more information, see the \fBCONSERVATIVE UPDATING\fR section of bundle install(1) \fIbundle\-install\.1\.html\fR\.
+.
.P
Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent indirect dependencies from being updated\.
+.
.SH "PATCH LEVEL OPTIONS"
Version 1\.14 introduced 4 patch\-level options that will influence how gem versions are resolved\. One of the following options can be used: \fB\-\-patch\fR, \fB\-\-minor\fR or \fB\-\-major\fR\. \fB\-\-strict\fR can be added to further influence resolution\.
+.
.TP
\fB\-\-patch\fR
Prefer updating only to next patch version\.
+.
.TP
\fB\-\-minor\fR
Prefer updating only to next minor version\.
+.
.TP
\fB\-\-major\fR
Prefer updating to next major version (default)\.
+.
.TP
\fB\-\-strict\fR
Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\.
+.
.P
-When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don't satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order\.
+When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don\'t satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order\.
+.
.P
Providing one of the patch level options (e\.g\. \fB\-\-patch\fR) changes the sort order of the satisfying versions, causing Bundler to consider the latest \fB\-\-patch\fR or \fB\-\-minor\fR version available before other versions\. Note that versions outside the stated patch level could still be resolved to if necessary to find a suitable dependency graph\.
+.
.P
-For example, if gem 'foo' is locked at 1\.0\.2, with no gem requirement defined in the Gemfile, and versions 1\.0\.3, 1\.0\.4, 1\.1\.0, 1\.1\.1, 2\.0\.0 all exist, the default order of preference by default (\fB\-\-major\fR) will be "2\.0\.0, 1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\.
+For example, if gem \'foo\' is locked at 1\.0\.2, with no gem requirement defined in the Gemfile, and versions 1\.0\.3, 1\.0\.4, 1\.1\.0, 1\.1\.1, 2\.0\.0 all exist, the default order of preference by default (\fB\-\-major\fR) will be "2\.0\.0, 1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\.
+.
.P
If the \fB\-\-patch\fR option is used, the order of preference will change to "1\.0\.4, 1\.0\.3, 1\.0\.2, 1\.1\.1, 1\.1\.0, 2\.0\.0"\.
+.
.P
If the \fB\-\-minor\fR option is used, the order of preference will change to "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2, 2\.0\.0"\.
+.
.P
Combining the \fB\-\-strict\fR option with any of the patch level options will remove any versions beyond the scope of the patch level option, to ensure that no gem is updated that far\.
+.
.P
To continue the previous example, if both \fB\-\-patch\fR and \fB\-\-strict\fR options are used, the available versions for resolution would be "1\.0\.4, 1\.0\.3, 1\.0\.2"\. If \fB\-\-minor\fR and \fB\-\-strict\fR are used, it would be "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\.
+.
.P
-Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available\. If the gem requirement for \fBfoo\fR in the Gemfile is '~> 1\.0', that will accomplish the same thing as providing the \fB\-\-minor\fR and \fB\-\-strict\fR options\.
+Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available\. If the gem requirement for \fBfoo\fR in the Gemfile is \'~> 1\.0\', that will accomplish the same thing as providing the \fB\-\-minor\fR and \fB\-\-strict\fR options\.
+.
.SH "PATCH LEVEL EXAMPLES"
Given the following gem specifications:
+.
.IP "" 4
+.
.nf
+
foo 1\.4\.3, requires: ~> bar 2\.0
foo 1\.4\.4, requires: ~> bar 2\.0
foo 1\.4\.5, requires: ~> bar 2\.1
foo 1\.5\.0, requires: ~> bar 2\.1
foo 1\.5\.1, requires: ~> bar 3\.0
bar with versions 2\.0\.3, 2\.0\.4, 2\.1\.0, 2\.1\.1, 3\.0\.0
+.
.fi
+.
.IP "" 0
+.
.P
Gemfile:
+.
.IP "" 4
+.
.nf
-gem 'foo'
+
+gem \'foo\'
+.
.fi
+.
.IP "" 0
+.
.P
Gemfile\.lock:
+.
.IP "" 4
+.
.nf
+
foo (1\.4\.3)
bar (~> 2\.0)
bar (2\.0\.3)
+.
.fi
+.
.IP "" 0
+.
.P
Cases:
+.
.IP "" 4
+.
.nf
+
# Command Line Result
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
-1 bundle update \-\-patch 'foo 1\.4\.5', 'bar 2\.1\.1'
-2 bundle update \-\-patch foo 'foo 1\.4\.5', 'bar 2\.1\.1'
-3 bundle update \-\-minor 'foo 1\.5\.1', 'bar 3\.0\.0'
-4 bundle update \-\-minor \-\-strict 'foo 1\.5\.0', 'bar 2\.1\.1'
-5 bundle update \-\-patch \-\-strict 'foo 1\.4\.4', 'bar 2\.0\.4'
+1 bundle update \-\-patch \'foo 1\.4\.5\', \'bar 2\.1\.1\'
+2 bundle update \-\-patch foo \'foo 1\.4\.5\', \'bar 2\.1\.1\'
+3 bundle update \-\-minor \'foo 1\.5\.1\', \'bar 3\.0\.0\'
+4 bundle update \-\-minor \-\-strict \'foo 1\.5\.0\', \'bar 2\.1\.1\'
+5 bundle update \-\-patch \-\-strict \'foo 1\.4\.4\', \'bar 2\.0\.4\'
+.
.fi
+.
.IP "" 0
+.
.P
In case 1, bar is upgraded to 2\.1\.1, a minor version increase, because the dependency from foo 1\.4\.5 required it\.
+.
.P
-In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it's not a declared dependency in the Gemfile\.
+In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it\'s not a declared dependency in the Gemfile\.
+.
.P
In case 3, bar goes up a whole major release, because a minor increase is preferred now for foo, and when it goes to 1\.5\.1, it requires 3\.0\.0 of bar\.
+.
.P
-In case 4, foo is preferred up to a minor version, but 1\.5\.1 won't work because the \-\-strict flag removes bar 3\.0\.0 from consideration since it's a major increment\.
+In case 4, foo is preferred up to a minor version, but 1\.5\.1 won\'t work because the \-\-strict flag removes bar 3\.0\.0 from consideration since it\'s a major increment\.
+.
.P
In case 5, both foo and bar have any minor or major increments removed from consideration because of the \-\-strict flag, so the most they can move is up to 1\.4\.4 and 2\.0\.4\.
+.
.SH "RECOMMENDED WORKFLOW"
In general, when working with an application managed with bundler, you should use the following workflow:
+.
.IP "\(bu" 4
After you create your Gemfile(5) for the first time, run
+.
.IP
$ bundle install
+.
.IP "\(bu" 4
Check the resulting \fBGemfile\.lock\fR into version control
+.
.IP
$ git add Gemfile\.lock
+.
.IP "\(bu" 4
When checking out this repository on another development machine, run
+.
.IP
$ bundle install
+.
.IP "\(bu" 4
When checking out this repository on a deployment machine, run
+.
.IP
$ bundle install \-\-deployment
+.
.IP "\(bu" 4
After changing the Gemfile(5) to reflect a new or update dependency, run
+.
.IP
$ bundle install
+.
.IP "\(bu" 4
Make sure to check the updated \fBGemfile\.lock\fR into version control
+.
.IP
$ git add Gemfile\.lock
+.
.IP "\(bu" 4
If bundle install(1) \fIbundle\-install\.1\.html\fR reports a conflict, manually update the specific gems that you changed in the Gemfile(5)
+.
.IP
$ bundle update rails thin
+.
.IP "\(bu" 4
If you want to update all the gems to the latest possible versions that still match the gems listed in the Gemfile(5), run
+.
.IP
$ bundle update \-\-all
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1
index a29858181a..bb03e8b5d6 100644
--- a/lib/bundler/man/bundle-version.1
+++ b/lib/bundler/man/bundle-version.1
@@ -1,22 +1,35 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-VERSION" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-VERSION" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-version\fR \- Prints Bundler version information
+.
.SH "SYNOPSIS"
\fBbundle version\fR
+.
.SH "DESCRIPTION"
Prints Bundler version information\.
+.
.SH "OPTIONS"
No options\.
+.
.SH "EXAMPLE"
Print the version of Bundler with build date and commit hash of the in the Git source\.
+.
.IP "" 4
+.
.nf
+
bundle version
+.
.fi
+.
.IP "" 0
+.
.P
shows \fBBundler version 2\.3\.21 (2022\-08\-24 commit d54be5fdd8)\fR for example\.
+.
.P
cf\. \fBbundle \-\-version\fR shows \fBBundler version 2\.3\.21\fR\.
diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1
index 9609e098dd..23fb95b738 100644
--- a/lib/bundler/man/bundle-viz.1
+++ b/lib/bundler/man/bundle-viz.1
@@ -1,29 +1,41 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-VIZ" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-VIZ" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile
+.
.SH "SYNOPSIS"
\fBbundle viz\fR [\-\-file=FILE] [\-\-format=FORMAT] [\-\-requirements] [\-\-version] [\-\-without=GROUP GROUP]
+.
.SH "DESCRIPTION"
\fBviz\fR generates a PNG file of the current \fBGemfile(5)\fR as a dependency graph\. \fBviz\fR requires the ruby\-graphviz gem (and its dependencies)\.
+.
.P
The associated gems must also be installed via \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR\.
+.
.P
\fBviz\fR command was deprecated in Bundler 2\.2\. Use bundler\-graph plugin \fIhttps://github\.com/rubygems/bundler\-graph\fR instead\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-file\fR, \fB\-f\fR
The name to use for the generated file\. See \fB\-\-format\fR option
+.
.TP
\fB\-\-format\fR, \fB\-F\fR
-This is output format option\. Supported format is png, jpg, svg, dot \|\.\|\.\|\.
+This is output format option\. Supported format is png, jpg, svg, dot \.\.\.
+.
.TP
\fB\-\-requirements\fR, \fB\-R\fR
Set to show the version of each required dependency\.
+.
.TP
\fB\-\-version\fR, \fB\-v\fR
Set to show each gem version\.
+.
.TP
\fB\-\-without\fR, \fB\-W\fR
Exclude gems that are part of the specified named group\.
diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1
index d84d788748..39f3807f30 100644
--- a/lib/bundler/man/bundle.1
+++ b/lib/bundler/man/bundle.1
@@ -1,102 +1,141 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE" "1" "January 2023" "" ""
+.
.SH "NAME"
\fBbundle\fR \- Ruby Dependency Management
+.
.SH "SYNOPSIS"
\fBbundle\fR COMMAND [\-\-no\-color] [\-\-verbose] [ARGS]
+.
.SH "DESCRIPTION"
-Bundler manages an \fBapplication's dependencies\fR through its entire life across many machines systematically and repeatably\.
+Bundler manages an \fBapplication\'s dependencies\fR through its entire life across many machines systematically and repeatably\.
+.
.P
See the bundler website \fIhttps://bundler\.io\fR for information on getting started, and Gemfile(5) for more information on the \fBGemfile\fR format\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-no\-color\fR
Print all output without color
+.
.TP
\fB\-\-retry\fR, \fB\-r\fR
Specify the number of times you wish to attempt network commands
+.
.TP
\fB\-\-verbose\fR, \fB\-V\fR
Print out additional logging information
+.
.SH "BUNDLE COMMANDS"
We divide \fBbundle\fR subcommands into primary commands and utilities:
+.
.SH "PRIMARY COMMANDS"
+.
.TP
\fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR
Install the gems specified by the \fBGemfile\fR or \fBGemfile\.lock\fR
+.
.TP
\fBbundle update(1)\fR \fIbundle\-update\.1\.html\fR
Update dependencies to their latest versions
+.
.TP
\fBbundle cache(1)\fR \fIbundle\-cache\.1\.html\fR
Package the \.gem files required by your application into the \fBvendor/cache\fR directory (aliases: \fBbundle package\fR, \fBbundle pack\fR)
+.
.TP
\fBbundle exec(1)\fR \fIbundle\-exec\.1\.html\fR
Execute a script in the current bundle
+.
.TP
\fBbundle config(1)\fR \fIbundle\-config\.1\.html\fR
Specify and read configuration options for Bundler
+.
.TP
\fBbundle help(1)\fR \fIbundle\-help\.1\.html\fR
Display detailed help for each subcommand
+.
.SH "UTILITIES"
+.
.TP
\fBbundle add(1)\fR \fIbundle\-add\.1\.html\fR
Add the named gem to the Gemfile and run \fBbundle install\fR
+.
.TP
\fBbundle binstubs(1)\fR \fIbundle\-binstubs\.1\.html\fR
Generate binstubs for executables in a gem
+.
.TP
\fBbundle check(1)\fR \fIbundle\-check\.1\.html\fR
Determine whether the requirements for your application are installed and available to Bundler
+.
.TP
\fBbundle show(1)\fR \fIbundle\-show\.1\.html\fR
Show the source location of a particular gem in the bundle
+.
.TP
\fBbundle outdated(1)\fR \fIbundle\-outdated\.1\.html\fR
Show all of the outdated gems in the current bundle
+.
.TP
\fBbundle console(1)\fR (deprecated)
Start an IRB session in the current bundle
+.
.TP
\fBbundle open(1)\fR \fIbundle\-open\.1\.html\fR
Open an installed gem in the editor
+.
.TP
\fBbundle lock(1)\fR \fIbundle\-lock\.1\.html\fR
Generate a lockfile for your dependencies
+.
.TP
\fBbundle viz(1)\fR \fIbundle\-viz\.1\.html\fR (deprecated)
Generate a visual representation of your dependencies
+.
.TP
\fBbundle init(1)\fR \fIbundle\-init\.1\.html\fR
Generate a simple \fBGemfile\fR, placed in the current directory
+.
.TP
\fBbundle gem(1)\fR \fIbundle\-gem\.1\.html\fR
Create a simple gem, suitable for development with Bundler
+.
.TP
\fBbundle platform(1)\fR \fIbundle\-platform\.1\.html\fR
Display platform compatibility information
+.
.TP
\fBbundle clean(1)\fR \fIbundle\-clean\.1\.html\fR
Clean up unused gems in your Bundler directory
+.
.TP
\fBbundle doctor(1)\fR \fIbundle\-doctor\.1\.html\fR
Display warnings about common problems
+.
.TP
\fBbundle remove(1)\fR \fIbundle\-remove\.1\.html\fR
Removes gems from the Gemfile
+.
.TP
\fBbundle plugin(1)\fR \fIbundle\-plugin\.1\.html\fR
Manage Bundler plugins
+.
.TP
\fBbundle version(1)\fR \fIbundle\-version\.1\.html\fR
Prints Bundler version information
+.
.SH "PLUGINS"
-When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named \fBbundler\-<command>\fR and execute it, passing down any extra arguments to it\.
+When running a command that isn\'t listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named \fBbundler\-<command>\fR and execute it, passing down any extra arguments to it\.
+.
.SH "OBSOLETE"
These commands are obsolete and should no longer be used:
+.
.IP "\(bu" 4
\fBbundle inject(1)\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5
index f24a1c540d..740a01e0cc 100644
--- a/lib/bundler/man/gemfile.5
+++ b/lib/bundler/man/gemfile.5
@@ -1,143 +1,215 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "GEMFILE" "5" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "GEMFILE" "5" "January 2023" "" ""
+.
.SH "NAME"
\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs
+.
.SH "SYNOPSIS"
A \fBGemfile\fR describes the gem dependencies required to execute associated Ruby code\.
+.
.P
Place the \fBGemfile\fR in the root of the directory containing the associated code\. For instance, in a Rails application, place the \fBGemfile\fR in the same directory as the \fBRakefile\fR\.
+.
.SH "SYNTAX"
A \fBGemfile\fR is evaluated as Ruby code, in a context which makes available a number of methods used to describe the gem requirements\.
+.
.SH "GLOBAL SOURCE"
At the top of the \fBGemfile\fR, add a single line for the \fBRubyGems\fR source that contains the gems listed in the \fBGemfile\fR\.
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
+.
.fi
+.
.IP "" 0
+.
.P
You can add only one global source\. In Bundler 1\.13, adding multiple global sources was deprecated\. The \fBsource\fR \fBMUST\fR be a valid RubyGems repository\.
+.
.P
To use more than one source of RubyGems, you should use \fI\fBsource\fR block\fR\.
+.
.P
A source is checked for gems following the heuristics described in \fISOURCE PRIORITY\fR\.
+.
.P
\fBNote about a behavior of the feature deprecated in Bundler 1\.13\fR: If a gem is found in more than one global source, Bundler will print a warning after installing the gem indicating which source was used, and listing the other sources where the gem is available\. A specific source can be selected for gems that need to use a non\-standard repository, suppressing this warning, by using the \fI\fB:source\fR option\fR or \fBsource\fR block\.
+.
.SS "CREDENTIALS"
Some gem sources require a username and password\. Use bundle config(1) \fIbundle\-config\.1\.html\fR to set the username and password for any of the sources that need it\. The command must be run once on each computer that will install the Gemfile, but this keeps the credentials from being stored in plain text in version control\.
+.
.IP "" 4
+.
.nf
+
bundle config gems\.example\.com user:password
+.
.fi
+.
.IP "" 0
+.
.P
For some sources, like a company Gemfury account, it may be easier to include the credentials in the Gemfile as part of the source URL\.
+.
.IP "" 4
+.
.nf
+
source "https://user:password@gems\.example\.com"
+.
.fi
+.
.IP "" 0
+.
.P
Credentials in the source URL will take precedence over credentials set using \fBconfig\fR\.
+.
.SH "RUBY"
If your application requires a specific Ruby version or engine, specify your requirements using the \fBruby\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\.
+.
.SS "VERSION (required)"
The version of Ruby that your application requires\. If your application requires an alternate Ruby engine, such as JRuby, TruffleRuby, etc\., this should be the Ruby version that the engine is compatible with\.
+.
.IP "" 4
+.
.nf
+
ruby "3\.1\.2"
+.
.fi
+.
.IP "" 0
-.P
-If you wish to derive your Ruby version from a version file (ie \.ruby\-version), you can use the \fBfile\fR option instead\.
-.IP "" 4
-.nf
-ruby file: "\.ruby\-version"
-.fi
-.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\.
+.
.P
-What exactly is an Engine?
-.IP "\(bu" 4
-A Ruby engine is an implementation of the Ruby language\.
+What exactly is an Engine? \- A Ruby engine is an implementation of the Ruby language\.
+.
.IP "\(bu" 4
-For background: the reference or original implementation of the Ruby programming language is called Matz's Ruby Interpreter \fIhttps://en\.wikipedia\.org/wiki/Ruby_MRI\fR, or MRI for short\. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz\. MRI is also known as CRuby, because it is written in C\. MRI is the most widely used Ruby engine\.
+For background: the reference or original implementation of the Ruby programming language is called Matz\'s Ruby Interpreter \fIhttps://en\.wikipedia\.org/wiki/Ruby_MRI\fR, or MRI for short\. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz\. MRI is also known as CRuby, because it is written in C\. MRI is the most widely used Ruby engine\.
+.
.IP "\(bu" 4
-Other implementations \fIhttps://www\.ruby\-lang\.org/en/about/\fR of Ruby exist\. Some of the more well\-known implementations include JRuby \fIhttps://www\.jruby\.org/\fR and TruffleRuby \fIhttps://www\.graalvm\.org/ruby/\fR\. Rubinius is an alternative implementation of Ruby written in Ruby\. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine\. TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM\.
+Other implementations \fIhttps://www\.ruby\-lang\.org/en/about/\fR of Ruby exist\. Some of the more well\-known implementations include JRuby \fIhttp://jruby\.org/\fR and TruffleRuby \fIhttps://www\.graalvm\.org/ruby/\fR\. Rubinius is an alternative implementation of Ruby written in Ruby\. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine\. TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM\.
+.
.IP "" 0
+.
.SS "ENGINE VERSION"
Each application \fImay\fR specify a Ruby engine version\. If an engine version is specified, an engine \fImust\fR also be specified\. If the engine is "ruby" the engine version specified \fImust\fR match the Ruby version\.
+.
.IP "" 4
+.
.nf
+
ruby "2\.6\.8", engine: "jruby", engine_version: "9\.3\.8\.0"
+.
.fi
+.
.IP "" 0
+.
.SS "PATCHLEVEL"
Each application \fImay\fR specify a Ruby patchlevel\. Specifying the patchlevel has been meaningless since Ruby 2\.1\.0 was released as the patchlevel is now uniquely determined by a combination of major, minor, and teeny version numbers\.
+.
.P
This option was implemented in Bundler 1\.4\.0 for Ruby 2\.0 or earlier\.
+.
.IP "" 4
+.
.nf
+
ruby "3\.1\.2", patchlevel: "20"
+.
.fi
+.
.IP "" 0
+.
.SH "GEMS"
Specify gem requirements using the \fBgem\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\.
+.
.SS "NAME (required)"
For each gem requirement, list a single \fIgem\fR line\.
+.
.IP "" 4
+.
.nf
+
gem "nokogiri"
+.
.fi
+.
.IP "" 0
+.
.SS "VERSION"
Each \fIgem\fR \fBMAY\fR have one or more version specifiers\.
+.
.IP "" 4
+.
.nf
+
gem "nokogiri", ">= 1\.4\.2"
gem "RedCloth", ">= 4\.1\.0", "< 4\.2\.0"
+.
.fi
+.
.IP "" 0
+.
.SS "REQUIRE AS"
Each \fIgem\fR \fBMAY\fR specify files that should be used when autorequiring via \fBBundler\.require\fR\. You may pass an array with multiple files or \fBtrue\fR if the file you want \fBrequired\fR has the same name as \fIgem\fR or \fBfalse\fR to prevent any file from being autorequired\.
+.
.IP "" 4
+.
.nf
+
gem "redis", require: ["redis/connection/hiredis", "redis"]
gem "webmock", require: false
gem "byebug", require: true
+.
.fi
+.
.IP "" 0
+.
.P
The argument defaults to the name of the gem\. For example, these are identical:
+.
.IP "" 4
+.
.nf
+
gem "nokogiri"
gem "nokogiri", require: "nokogiri"
gem "nokogiri", require: true
+.
.fi
+.
.IP "" 0
+.
.SS "GROUPS"
Each \fIgem\fR \fBMAY\fR specify membership in one or more groups\. Any \fIgem\fR that does not specify membership in any group is placed in the \fBdefault\fR group\.
+.
.IP "" 4
+.
.nf
+
gem "rspec", group: :test
gem "wirble", groups: [:development, :test]
+.
.fi
+.
.IP "" 0
+.
.P
The Bundler runtime allows its two main methods, \fBBundler\.setup\fR and \fBBundler\.require\fR, to limit their impact to particular groups\.
+.
.IP "" 4
+.
.nf
-# setup adds gems to Ruby's load path
+
+# setup adds gems to Ruby\'s load path
Bundler\.setup # defaults to all groups
require "bundler/setup" # same as Bundler\.setup
Bundler\.setup(:default) # only set up the _default_ group
@@ -149,271 +221,429 @@ Bundler\.require # defaults to the _default_ group
Bundler\.require(:default) # identical
Bundler\.require(:default, :test) # requires the _default_ and _test_ groups
Bundler\.require(:test) # requires the _test_ group
+.
.fi
+.
.IP "" 0
+.
.P
The Bundler CLI allows you to specify a list of groups whose gems \fBbundle install\fR should not install with the \fBwithout\fR configuration\.
+.
.P
To specify multiple groups to ignore, specify a list of groups separated by spaces\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-local without test
bundle config set \-\-local without development test
+.
.fi
+.
.IP "" 0
+.
.P
Also, calling \fBBundler\.setup\fR with no parameters, or calling \fBrequire "bundler/setup"\fR will setup all groups except for the ones you excluded via \fB\-\-without\fR (since they are not available)\.
+.
.P
Note that on \fBbundle install\fR, bundler downloads and evaluates all gems, in order to create a single canonical list of all of the required gems and their dependencies\. This means that you cannot list different versions of the same gems in different groups\. For more details, see Understanding Bundler \fIhttps://bundler\.io/rationale\.html\fR\.
+.
.SS "PLATFORMS"
If a gem should only be used in a particular platform or set of platforms, you can specify them\. Platforms are essentially identical to groups, except that you do not need to use the \fB\-\-without\fR install\-time flag to exclude groups of gems for other platforms\.
+.
.P
There are a number of \fBGemfile\fR platforms:
+.
.TP
\fBruby\fR
C Ruby (MRI), Rubinius, or TruffleRuby, but not Windows
+.
.TP
\fBmri\fR
C Ruby (MRI) only, but not Windows
+.
.TP
\fBwindows\fR
Windows C Ruby (MRI), including RubyInstaller 32\-bit and 64\-bit versions
+.
.TP
\fBmswin\fR
Windows C Ruby (MRI), including RubyInstaller 32\-bit versions
+.
.TP
\fBmswin64\fR
Windows C Ruby (MRI), including RubyInstaller 64\-bit versions
+.
.TP
\fBrbx\fR
Rubinius
+.
.TP
\fBjruby\fR
JRuby
+.
.TP
\fBtruffleruby\fR
TruffleRuby
+.
.P
On platforms \fBruby\fR, \fBmri\fR, \fBmswin\fR, \fBmswin64\fR, and \fBwindows\fR, you may additionally specify a version by appending the major and minor version numbers without a delimiter\. For example, to specify that a gem should only be used on platform \fBruby\fR version 3\.1, use:
+.
.IP "" 4
+.
.nf
+
ruby_31
+.
.fi
+.
.IP "" 0
+.
.P
As with groups (above), you may specify one or more platforms:
+.
.IP "" 4
+.
.nf
+
gem "weakling", platforms: :jruby
gem "ruby\-debug", platforms: :mri_31
gem "nokogiri", platforms: [:windows_31, :jruby]
+.
.fi
+.
.IP "" 0
+.
.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
-.P
-Note that, while unfortunately using the same terminology, the values of this option are different from the values that \fBbundle lock \-\-add\-platform\fR can take\. The values of this option are more closer to "Ruby Implementation" while the values that \fBbundle lock \-\-add\-platform\fR understands are more related to OS and architecture of the different systems where your lockfile will be used\.
+.
.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:
+.
.IP "" 4
+.
.nf
+
gem "ffi", force_ruby_platform: true
+.
.fi
+.
.IP "" 0
+.
.P
This can be handy (assuming the pure ruby variant works fine) when:
+.
.IP "\(bu" 4
-You're having issues with the platform specific variant\.
+You\'re having issues with the platform specific variant\.
+.
.IP "\(bu" 4
The platform specific variant does not yet support a newer ruby (and thus has a \fBrequired_ruby_version\fR upper bound), but you still want your Gemfile{\.lock} files to resolve under that ruby\.
+.
.IP "" 0
+.
.SS "SOURCE"
-You can select an alternate RubyGems repository for a gem using the ':source' option\.
+You can select an alternate RubyGems repository for a gem using the \':source\' option\.
+.
.IP "" 4
+.
.nf
+
gem "some_internal_gem", source: "https://gems\.example\.com"
+.
.fi
+.
.IP "" 0
+.
.P
This forces the gem to be loaded from this source and ignores the global source declared at the top level of the file\. If the gem does not exist in this source, it will not be installed\.
+.
.P
Bundler will search for child dependencies of this gem by first looking in the source selected for the parent, but if they are not found there, it will fall back on the global source\.
+.
.P
\fBNote about a behavior of the feature deprecated in Bundler 1\.13\fR: Selecting a specific source repository this way also suppresses the ambiguous gem warning described above in \fIGLOBAL SOURCE\fR\.
+.
.P
Using the \fB:source\fR option for an individual gem will also make that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when adding gems with explicit sources, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources\.
+.
.SS "GIT"
If necessary, you can specify that a gem is located at a particular git repository using the \fB:git\fR parameter\. The repository can be accessed via several protocols:
+.
.TP
\fBHTTP(S)\fR
gem "rails", git: "https://github\.com/rails/rails\.git"
+.
.TP
\fBSSH\fR
gem "rails", git: "git@github\.com:rails/rails\.git"
+.
.TP
\fBgit\fR
gem "rails", git: "git://github\.com/rails/rails\.git"
+.
.P
If using SSH, the user that you use to run \fBbundle install\fR \fBMUST\fR have the appropriate keys available in their \fB$HOME/\.ssh\fR\.
+.
.P
\fBNOTE\fR: \fBhttp://\fR and \fBgit://\fR URLs should be avoided if at all possible\. These protocols are unauthenticated, so a man\-in\-the\-middle attacker can deliver malicious code and compromise your system\. HTTPS and SSH are strongly preferred\.
+.
.P
The \fBgroup\fR, \fBplatforms\fR, and \fBrequire\fR options are available and behave exactly the same as they would for a normal gem\.
+.
.P
A git repository \fBSHOULD\fR have at least one file, at the root of the directory containing the gem, with the extension \fB\.gemspec\fR\. This file \fBMUST\fR contain a valid gem specification, as expected by the \fBgem build\fR command\.
+.
.P
If a git repository does not have a \fB\.gemspec\fR, bundler will attempt to create one, but it will not contain any dependencies, executables, or C extension compilation instructions\. As a result, it may fail to properly integrate into your application\.
+.
.P
If a git repository does have a \fB\.gemspec\fR for the gem you attached it to, a version specifier, if provided, means that the git repository is only valid if the \fB\.gemspec\fR specifies a version matching the version specifier\. If not, bundler will print a warning\.
+.
.IP "" 4
+.
.nf
+
gem "rails", "2\.3\.8", git: "https://github\.com/rails/rails\.git"
# bundle install will fail, because the \.gemspec in the rails
-# repository's master branch specifies version 3\.0\.0
+# repository\'s master branch specifies version 3\.0\.0
+.
.fi
+.
.IP "" 0
+.
.P
If a git repository does \fBnot\fR have a \fB\.gemspec\fR for the gem you attached it to, a version specifier \fBMUST\fR be provided\. Bundler will use this version in the simple \fB\.gemspec\fR it creates\.
+.
.P
Git repositories support a number of additional options\.
+.
.TP
\fBbranch\fR, \fBtag\fR, and \fBref\fR
You \fBMUST\fR only specify at most one of these options\. The default is \fBbranch: "master"\fR\. For example:
+.
.IP
gem "rails", git: "https://github\.com/rails/rails\.git", branch: "5\-0\-stable"
+.
.IP
gem "rails", git: "https://github\.com/rails/rails\.git", tag: "v5\.0\.0"
+.
.IP
gem "rails", git: "https://github\.com/rails/rails\.git", ref: "4aded"
+.
.TP
\fBsubmodules\fR
For reference, a git submodule \fIhttps://git\-scm\.com/book/en/v2/Git\-Tools\-Submodules\fR lets you have another git repository within a subfolder of your repository\. Specify \fBsubmodules: true\fR to cause bundler to expand any submodules included in the git repository
+.
.P
If a git repository contains multiple \fB\.gemspecs\fR, each \fB\.gemspec\fR represents a gem located at the same place in the file system as the \fB\.gemspec\fR\.
+.
.IP "" 4
+.
.nf
+
|~rails [git root]
| |\-rails\.gemspec [rails gem located here]
|~actionpack
| |\-actionpack\.gemspec [actionpack gem located here]
|~activesupport
| |\-activesupport\.gemspec [activesupport gem located here]
-|\|\.\|\.\|\.
+|\.\.\.
+.
.fi
+.
.IP "" 0
+.
.P
To install a gem located in a git repository, bundler changes to the directory containing the gemspec, runs \fBgem build name\.gemspec\fR and then installs the resulting gem\. The \fBgem build\fR command, which comes standard with Rubygems, evaluates the \fB\.gemspec\fR in the context of the directory in which it is located\.
+.
.SS "GIT SOURCE"
-A custom git source can be defined via the \fBgit_source\fR method\. Provide the source's name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address:
+A custom git source can be defined via the \fBgit_source\fR method\. Provide the source\'s name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address:
+.
.IP "" 4
+.
.nf
+
git_source(:stash){ |repo_name| "https://stash\.corp\.acme\.pl/#{repo_name}\.git" }
-gem 'rails', stash: 'forks/rails'
+gem \'rails\', stash: \'forks/rails\'
+.
.fi
+.
.IP "" 0
+.
.P
In addition, if you wish to choose a specific branch:
+.
.IP "" 4
+.
.nf
+
gem "rails", stash: "forks/rails", branch: "branch_name"
+.
.fi
+.
.IP "" 0
+.
.SS "GITHUB"
\fBNOTE\fR: This shorthand should be avoided until Bundler 2\.0, since it currently expands to an insecure \fBgit://\fR URL\. This allows a man\-in\-the\-middle attacker to compromise your system\.
+.
.P
If the git repository you want to use is hosted on GitHub and is public, you can use the :github shorthand to specify the github username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\.
+.
.IP "" 4
+.
.nf
+
gem "rails", github: "rails/rails"
gem "rails", github: "rails"
+.
.fi
+.
.IP "" 0
+.
.P
Are both equivalent to
+.
.IP "" 4
+.
.nf
+
gem "rails", git: "https://github\.com/rails/rails\.git"
+.
.fi
+.
.IP "" 0
+.
.P
Since the \fBgithub\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\.
+.
.P
You can also directly pass a pull request URL:
+.
.IP "" 4
+.
.nf
+
gem "rails", github: "https://github\.com/rails/rails/pull/43753"
+.
.fi
+.
.IP "" 0
+.
.P
Which is equivalent to:
+.
.IP "" 4
+.
.nf
+
gem "rails", github: "rails/rails", branch: "refs/pull/43753/head"
+.
.fi
+.
.IP "" 0
+.
.SS "GIST"
If the git repository you want to use is hosted as a GitHub Gist and is public, you can use the :gist shorthand to specify the gist identifier (without the trailing "\.git")\.
+.
.IP "" 4
+.
.nf
+
gem "the_hatch", gist: "4815162342"
+.
.fi
+.
.IP "" 0
+.
.P
Is equivalent to:
+.
.IP "" 4
+.
.nf
+
gem "the_hatch", git: "https://gist\.github\.com/4815162342\.git"
+.
.fi
+.
.IP "" 0
+.
.P
Since the \fBgist\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\.
+.
.SS "BITBUCKET"
If the git repository you want to use is hosted on Bitbucket and is public, you can use the :bitbucket shorthand to specify the bitbucket username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\.
+.
.IP "" 4
+.
.nf
+
gem "rails", bitbucket: "rails/rails"
gem "rails", bitbucket: "rails"
+.
.fi
+.
.IP "" 0
+.
.P
Are both equivalent to
+.
.IP "" 4
+.
.nf
+
gem "rails", git: "https://rails@bitbucket\.org/rails/rails\.git"
+.
.fi
+.
.IP "" 0
+.
.P
Since the \fBbitbucket\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\.
+.
.SS "PATH"
You can specify that a gem is located in a particular location on the file system\. Relative paths are resolved relative to the directory containing the \fBGemfile\fR\.
+.
.P
Similar to the semantics of the \fB:git\fR option, the \fB:path\fR option requires that the directory in question either contains a \fB\.gemspec\fR for the gem, or that you specify an explicit version that bundler should use\.
+.
.P
Unlike \fB:git\fR, bundler does not compile C extensions for gems specified as paths\.
+.
.IP "" 4
+.
.nf
+
gem "rails", path: "vendor/rails"
+.
.fi
+.
.IP "" 0
+.
.P
-If you would like to use multiple local gems directly from the filesystem, you can set a global \fBpath\fR option to the path containing the gem's files\. This will automatically load gemspec files from subdirectories\.
+If you would like to use multiple local gems directly from the filesystem, you can set a global \fBpath\fR option to the path containing the gem\'s files\. This will automatically load gemspec files from subdirectories\.
+.
.IP "" 4
+.
.nf
-path 'components' do
- gem 'admin_ui'
- gem 'public_ui'
+
+path \'components\' do
+ gem \'admin_ui\'
+ gem \'public_ui\'
end
+.
.fi
+.
.IP "" 0
+.
.SH "BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS"
The \fB:source\fR, \fB:git\fR, \fB:path\fR, \fB:group\fR, and \fB:platforms\fR options may be applied to a group of gems by using block form\.
+.
.IP "" 4
+.
.nf
+
source "https://gems\.example\.com" do
gem "some_internal_gem"
gem "another_internal_gem"
@@ -433,40 +663,61 @@ group :development, optional: true do
gem "wirble"
gem "faker"
end
+.
.fi
+.
.IP "" 0
+.
.P
In the case of the group block form the :optional option can be given to prevent a group from being installed unless listed in the \fB\-\-with\fR option given to the \fBbundle install\fR command\.
+.
.P
In the case of the \fBgit\fR block form, the \fB:ref\fR, \fB:branch\fR, \fB:tag\fR, and \fB:submodules\fR options may be passed to the \fBgit\fR method, and all gems in the block will inherit those options\.
+.
.P
The presence of a \fBsource\fR block in a Gemfile also makes that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when defining source blocks, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources, either via source blocks or \fB:source\fR directives on individual gems\.
+.
.SH "INSTALL_IF"
The \fBinstall_if\fR method allows gems to be installed based on a proc or lambda\. This is especially useful for optional gems that can only be used if certain software is installed or some other conditions are met\.
+.
.IP "" 4
+.
.nf
+
install_if \-> { RUBY_PLATFORM =~ /darwin/ } do
gem "pasteboard"
end
+.
.fi
+.
.IP "" 0
+.
.SH "GEMSPEC"
-The \fB\.gemspec\fR \fIhttps://guides\.rubygems\.org/specification\-reference/\fR file is where you provide metadata about your gem to Rubygems\. Some required Gemspec attributes include the name, description, and homepage of your gem\. This is also where you specify the dependencies your gem needs to run\.
+The \fB\.gemspec\fR \fIhttp://guides\.rubygems\.org/specification\-reference/\fR file is where you provide metadata about your gem to Rubygems\. Some required Gemspec attributes include the name, description, and homepage of your gem\. This is also where you specify the dependencies your gem needs to run\.
+.
.P
If you wish to use Bundler to help install dependencies for a gem while it is being developed, use the \fBgemspec\fR method to pull in the dependencies listed in the \fB\.gemspec\fR file\.
+.
.P
-The \fBgemspec\fR method adds any runtime dependencies as gem requirements in the default group\. It also adds development dependencies as gem requirements in the \fBdevelopment\fR group\. Finally, it adds a gem requirement on your project (\fBpath: '\.'\fR)\. In conjunction with \fBBundler\.setup\fR, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths\.
+The \fBgemspec\fR method adds any runtime dependencies as gem requirements in the default group\. It also adds development dependencies as gem requirements in the \fBdevelopment\fR group\. Finally, it adds a gem requirement on your project (\fBpath: \'\.\'\fR)\. In conjunction with \fBBundler\.setup\fR, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths\.
+.
.P
-The \fBgemspec\fR method supports optional \fB:path\fR, \fB:glob\fR, \fB:name\fR, and \fB:development_group\fR options, which control where bundler looks for the \fB\.gemspec\fR, the glob it uses to look for the gemspec (defaults to: \fB{,*,*/*}\.gemspec\fR), what named \fB\.gemspec\fR it uses (if more than one is present), and which group development dependencies are included in\.
+The \fBgemspec\fR method supports optional \fB:path\fR, \fB:glob\fR, \fB:name\fR, and \fB:development_group\fR options, which control where bundler looks for the \fB\.gemspec\fR, the glob it uses to look for the gemspec (defaults to: "{,\fI,\fR/*}\.gemspec"), what named \fB\.gemspec\fR it uses (if more than one is present), and which group development dependencies are included in\.
+.
.P
When a \fBgemspec\fR dependency encounters version conflicts during resolution, the local version under development will always be selected \-\- even if there are remote versions that better match other requirements for the \fBgemspec\fR gem\.
+.
.SH "SOURCE PRIORITY"
When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order:
+.
.IP "1." 4
The source explicitly attached to the gem (using \fB:source\fR, \fB:path\fR, or \fB:git\fR)
+.
.IP "2." 4
For implicit gems (dependencies of explicit gems), any source, git, or path repository declared on the parent\. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from \fBrubygems\.org\fR
+.
.IP "3." 4
If neither of the above conditions are met, the global source will be used\. If multiple global sources are specified, they will be prioritized from last to first, but this is deprecated since Bundler 1\.13, so Bundler prints a warning and will abort with an error in the future\.
+.
.IP "" 0
diff --git a/lib/bundler/man/gemfile.5.ronn b/lib/bundler/man/gemfile.5.ronn
index 802549737e..a3affc30cc 100644
--- a/lib/bundler/man/gemfile.5.ronn
+++ b/lib/bundler/man/gemfile.5.ronn
@@ -69,16 +69,6 @@ should be the Ruby version that the engine is compatible with.
ruby "3.1.2"
-If you wish to derive your Ruby version from a version file (ie .ruby-version),
-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
@@ -96,7 +86,7 @@ What exactly is an Engine?
- [Other implementations](https://www.ruby-lang.org/en/about/) of Ruby exist.
Some of the more well-known implementations include
- [JRuby](https://www.jruby.org/) and [TruffleRuby](https://www.graalvm.org/ruby/).
+ [JRuby](http://jruby.org/) and [TruffleRuby](https://www.graalvm.org/ruby/).
Rubinius is an alternative implementation of Ruby written in Ruby.
JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine.
TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM.
@@ -238,16 +228,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`
-
-Note that, while unfortunately using the same terminology, the values of this
-option are different from the values that `bundle lock --add-platform` can take.
-The values of this option are more closer to "Ruby Implementation" while the
-values that `bundle lock --add-platform` understands are more related to OS and
-architecture of the different systems where your lockfile will be used.
-
### FORCE_RUBY_PLATFORM
If you always want the pure ruby variant of a gem to be chosen over platform
@@ -515,7 +495,7 @@ software is installed or some other conditions are met.
## GEMSPEC
-The [`.gemspec`](https://guides.rubygems.org/specification-reference/) file is where
+The [`.gemspec`](http://guides.rubygems.org/specification-reference/) file is where
you provide metadata about your gem to Rubygems. Some required Gemspec
attributes include the name, description, and homepage of your gem. This is
also where you specify the dependencies your gem needs to run.
@@ -534,7 +514,7 @@ paths.
The `gemspec` method supports optional `:path`, `:glob`, `:name`, and `:development_group`
options, which control where bundler looks for the `.gemspec`, the glob it uses to look
-for the gemspec (defaults to: `{,*,*/*}.gemspec`), what named `.gemspec` it uses
+for the gemspec (defaults to: "{,*,*/*}.gemspec"), what named `.gemspec` it uses
(if more than one is present), and which group development dependencies are included in.
When a `gemspec` dependency encounters version conflicts during resolution, the
diff --git a/lib/bundler/match_metadata.rb b/lib/bundler/match_metadata.rb
index f6cc27df32..499036ca93 100644
--- a/lib/bundler/match_metadata.rb
+++ b/lib/bundler/match_metadata.rb
@@ -2,10 +2,6 @@
module Bundler
module MatchMetadata
- def matches_current_metadata?
- matches_current_ruby? && matches_current_rubygems?
- end
-
def matches_current_ruby?
@required_ruby_version.satisfied_by?(Gem.ruby_version)
end
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/mirror.rb b/lib/bundler/mirror.rb
index 494a6d6aef..9d437a0951 100644
--- a/lib/bundler/mirror.rb
+++ b/lib/bundler/mirror.rb
@@ -47,7 +47,7 @@ module Bundler
def fetch_valid_mirror_for(uri)
downcased = uri.to_s.downcase
- mirror = @mirrors[downcased] || @mirrors[Gem::URI(downcased).host] || Mirror.new(uri)
+ mirror = @mirrors[downcased] || @mirrors[Bundler::URI(downcased).host] || Mirror.new(uri)
mirror.validate!(@prober)
mirror = Mirror.new(uri) unless mirror.valid?
mirror
@@ -74,7 +74,7 @@ module Bundler
@uri = if uri.nil?
nil
else
- Gem::URI(uri.to_s)
+ Bundler::URI(uri.to_s)
end
@valid = nil
end
@@ -126,7 +126,7 @@ module Bundler
if uri == "all"
@all = true
else
- @uri = Gem::URI(uri).absolute? ? Settings.normalize_uri(uri) : uri
+ @uri = Bundler::URI(uri).absolute? ? Settings.normalize_uri(uri) : uri
end
@value = value
end
diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb
index 588fa79be8..26458bd596 100644
--- a/lib/bundler/plugin.rb
+++ b/lib/bundler/plugin.rb
@@ -15,7 +15,7 @@ module Bundler
class UnknownSourceError < PluginError; end
class PluginInstallError < PluginError; end
- PLUGIN_FILE_NAME = "plugins.rb"
+ PLUGIN_FILE_NAME = "plugins.rb".freeze
module_function
@@ -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
@@ -101,7 +100,7 @@ module Bundler
# @param [Pathname] gemfile path
# @param [Proc] block that can be evaluated for (inline) Gemfile
def gemfile_install(gemfile = nil, &inline)
- Bundler.settings.temporary(frozen: false, deployment: false) do
+ Bundler.settings.temporary(:frozen => false, :deployment => false) do
builder = DSL.new
if block_given?
builder.instance_eval(&inline)
@@ -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
@@ -307,7 +301,7 @@ module Bundler
@hooks_by_event = Hash.new {|h, k| h[k] = [] }
load_paths = spec.load_paths
- Gem.add_to_load_path(*load_paths)
+ Bundler.rubygems.add_to_load_path(load_paths)
path = Pathname.new spec.full_gem_path
begin
@@ -335,14 +329,13 @@ 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
# done to avoid conflicts
path = index.plugin_path(name)
- Gem.add_to_load_path(*index.load_paths(name))
+ Bundler.rubygems.add_to_load_path(index.load_paths(name))
load path.join(PLUGIN_FILE_NAME)
diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb
index 690f379389..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
@@ -96,7 +95,7 @@ module Bundler
#
# Note: Do not override if you don't know what you are doing.
def post_install(spec, disable_exts = false)
- opts = { env_shebang: false, disable_extensions: disable_exts }
+ opts = { :env_shebang => false, :disable_extensions => disable_exts }
installer = Bundler::Source::Path::Installer.new(spec, opts)
installer.post_install
end
@@ -107,7 +106,7 @@ module Bundler
def install_path
@install_path ||=
begin
- base_name = File.basename(Gem::URI.parse(uri).normalize.path)
+ base_name = File.basename(Bundler::URI.parse(uri).normalize.path)
gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}")
end
@@ -131,7 +130,7 @@ module Bundler
Bundler::Index.build do |index|
files.each do |file|
next unless spec = Bundler.load_gemspec(file)
- spec.installed_by_version = Gem::VERSION
+ Bundler.rubygems.set_installed_by_version(spec)
spec.source = self
Bundler.rubygems.validate(spec)
@@ -176,7 +175,7 @@ module Bundler
#
# This is used by `app_cache_path`
def app_cache_dirname
- base_name = File.basename(Gem::URI.parse(uri).normalize.path)
+ base_name = File.basename(Bundler::URI.parse(uri).normalize.path)
"#{base_name}-#{uri_hash}"
end
@@ -196,7 +195,6 @@ module Bundler
FileUtils.rm_rf(new_cache_path)
FileUtils.cp_r(install_path, new_cache_path)
- FileUtils.rm_rf(app_cache_path.join(".git"))
FileUtils.touch(app_cache_path.join(".bundlecache"))
end
diff --git a/lib/bundler/plugin/index.rb b/lib/bundler/plugin/index.rb
index c2ab8f90da..6fbd036f38 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
@@ -154,7 +146,7 @@ module Bundler
# @param [Boolean] is the index file global index
def load_index(index_file, global = false)
SharedHelpers.filesystem_access(index_file, :read) do |index_f|
- valid_file = index_f&.exist? && !index_f.size.zero?
+ valid_file = index_f && index_f.exist? && !index_f.size.zero?
break unless valid_file
data = index_f.read
diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb
index 4f60862bb4..81ecafa470 100644
--- a/lib/bundler/plugin/installer.rb
+++ b/lib/bundler/plugin/installer.rb
@@ -10,7 +10,6 @@ module Bundler
class Installer
autoload :Rubygems, File.expand_path("installer/rubygems", __dir__)
autoload :Git, File.expand_path("installer/git", __dir__)
- autoload :Path, File.expand_path("installer/path", __dir__)
def install(names, options)
check_sources_consistency!(options)
@@ -19,8 +18,8 @@ module Bundler
if options[:git]
install_git(names, version, options)
- elsif options[:path]
- install_path(names, version, options[:path])
+ elsif options[:local_git]
+ install_local_git(names, version, options)
else
sources = options[:source] || Gem.sources
install_rubygems(names, version, sources)
@@ -46,40 +45,20 @@ module Bundler
if options.key?(:git) && options.key?(:local_git)
raise InvalidOption, "Remote and local plugin git sources can't be both specified"
end
-
- # back-compat; local_git is an alias for git
- if options.key?(:local_git)
- Bundler::SharedHelpers.major_deprecation(2, "--local_git is deprecated, use --git")
- options[:git] = options.delete(:local_git)
- end
-
- if (options.keys & [:source, :git, :path]).length > 1
- raise InvalidOption, "Only one of --source, --git, or --path may be specified"
- end
-
- if (options.key?(:branch) || options.key?(:ref)) && !options.key?(:git)
- raise InvalidOption, "--#{options.key?(:branch) ? "branch" : "ref"} can only be used with git sources"
- end
-
- if options.key?(:branch) && options.key?(:ref)
- raise InvalidOption, "--branch and --ref can't be both specified"
- end
end
def install_git(names, version, options)
- source_list = SourceList.new
- source = source_list.add_git_source({ "uri" => options[:git],
- "branch" => options[:branch],
- "ref" => options[:ref] })
+ uri = options.delete(:git)
+ options["uri"] = uri
- install_all_sources(names, version, source_list, source)
+ install_all_sources(names, version, options, options[:source])
end
- def install_path(names, version, path)
- source_list = SourceList.new
- source = source_list.add_path_source({ "path" => path, "root_path" => SharedHelpers.pwd })
+ def install_local_git(names, version, options)
+ uri = options.delete(:local_git)
+ options["uri"] = uri
- install_all_sources(names, version, source_list, source)
+ install_all_sources(names, version, options, options[:source])
end
# Installs the plugin from rubygems source and returns the path where the
@@ -91,23 +70,21 @@ module Bundler
#
# @return [Hash] map of names to the specs of plugins installed
def install_rubygems(names, version, sources)
- source_list = SourceList.new
+ install_all_sources(names, version, nil, sources)
+ end
- Array(sources).each {|remote| source_list.add_global_rubygems_remote(remote) }
+ def install_all_sources(names, version, git_source_options, rubygems_source)
+ source_list = SourceList.new
- install_all_sources(names, version, source_list)
- end
+ source_list.add_git_source(git_source_options) if git_source_options
+ Array(rubygems_source).each {|remote| source_list.add_global_rubygems_remote(remote) } if rubygems_source
- def install_all_sources(names, version, source_list, source = nil)
- deps = names.map {|name| Dependency.new(name, version, { "source" => source }) }
+ deps = names.map {|name| Dependency.new name, version }
Bundler.configure_gem_home_and_path(Plugin.root)
- Bundler.settings.temporary(deployment: false, frozen: false) do
- definition = Definition.new(nil, deps, source_list, true)
-
- install_definition(definition)
- end
+ definition = Definition.new(nil, deps, source_list, true)
+ install_definition(definition)
end
# Installs the plugins and deps from the provided specs and returns map of
diff --git a/lib/bundler/plugin/installer/path.rb b/lib/bundler/plugin/installer/path.rb
deleted file mode 100644
index 58a8fa7426..0000000000
--- a/lib/bundler/plugin/installer/path.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- module Plugin
- class Installer
- class Path < Bundler::Source::Path
- def root
- SharedHelpers.in_bundle? ? Bundler.root : Plugin.root
- end
-
- def generate_bin(spec, disable_extensions = false)
- # Need to find a way without code duplication
- # For now, we can ignore this
- end
- end
- end
- end
-end
diff --git a/lib/bundler/plugin/source_list.rb b/lib/bundler/plugin/source_list.rb
index 746996de55..547661cf2f 100644
--- a/lib/bundler/plugin/source_list.rb
+++ b/lib/bundler/plugin/source_list.rb
@@ -9,10 +9,6 @@ module Bundler
add_source_to_list Plugin::Installer::Git.new(options), git_sources
end
- def add_path_source(options = {})
- add_source_to_list Plugin::Installer::Path.new(options), path_sources
- end
-
def add_rubygems_source(options = {})
add_source_to_list Plugin::Installer::Rubygems.new(options), @rubygems_sources
end
@@ -21,6 +17,10 @@ module Bundler
path_sources + git_sources + rubygems_sources + [metadata_source]
end
+ def default_source
+ git_sources.first || global_rubygems_source
+ end
+
private
def rubygems_aggregate_class
diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb
index 9d237f3fa0..34d7fd116c 100644
--- a/lib/bundler/remote_specification.rb
+++ b/lib/bundler/remote_specification.rb
@@ -29,8 +29,12 @@ module Bundler
@platform = _remote_specification.platform
end
+ def identifier
+ @__identifier ||= [name, version, @platform.to_s]
+ end
+
def full_name
- @full_name ||= if @platform == Gem::Platform::RUBY
+ if @platform == Gem::Platform::RUBY
"#{@name}-#{@version}"
else
"#{@name}-#{@version}-#{@platform}"
@@ -88,10 +92,6 @@ module Bundler
end
end
- def runtime_dependencies
- dependencies.select(&:runtime?)
- end
-
def git_version
return unless loaded_from && source.is_a?(Bundler::Source::Git)
" #{source.revision[0..6]}"
@@ -106,7 +106,7 @@ module Bundler
def _remote_specification
@_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform])
@_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \
- " missing from the server!")
+ " missing from the server! Try installing with `--full-index` as a workaround.")
end
def method_missing(method, *args, &blk)
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index a38b6974f8..8237ff53fe 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -29,7 +29,7 @@ module Bundler
Bundler.ui.info "Resolving dependencies...", true
- solve_versions(root: root, logger: logger)
+ solve_versions(:root => root, :logger => logger)
end
def setup_solver
@@ -37,39 +37,29 @@ 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] }
- end
-
- @all_versions = Hash.new do |candidates, package|
- candidates[package] = all_versions_for(package)
+ specs[name] = source_for(name).specs.search(name).sort_by {|s| [s.version, s.platform.to_s] }
end
@sorted_versions = Hash.new do |candidates, package|
- candidates[package] = filtered_versions_for(package).sort
+ candidates[package] = if package.root?
+ [root_version]
+ else
+ all_versions_for(package).sort
+ end
end
- @sorted_versions[root] = [root_version]
-
root_dependencies = prepare_dependencies(@requirements, @packages)
@cached_dependencies = Hash.new do |dependencies, package|
- dependencies[package] = Hash.new do |versions, version|
- versions[version] = to_dependency_hash(version.dependencies.reject {|d| d.name == package.name }, @packages)
+ dependencies[package] = if package.root?
+ { root_version => root_dependencies }
+ else
+ Hash.new do |versions, version|
+ versions[version] = to_dependency_hash(version.dependencies, @packages)
+ end
end
end
- @cached_dependencies[root] = { root_version => root_dependencies }
-
logger = Bundler::UI::Shell.new
logger.level = debug? ? "debug" : "warn"
@@ -77,16 +67,15 @@ module Bundler
end
def solve_versions(root:, logger:)
- solver = PubGrub::VersionSolver.new(source: self, root: root, logger: logger)
+ solver = PubGrub::VersionSolver.new(:source => self, :root => root, :logger => logger)
result = solver.solve
- resolved_specs = result.map {|package, version| version.to_specs(package) }.flatten
- resolved_specs |= @base.specs_compatible_with(SpecSet.new(resolved_specs))
+ result.map {|package, version| version.to_specs(package) }.flatten.uniq
rescue PubGrub::SolveFailure => e
incompatibility = e.incompatibility
- names_to_unlock, names_to_allow_prereleases_for, names_to_allow_remote_specs_for, extended_explanation = find_names_to_relax(incompatibility)
+ names_to_unlock, names_to_allow_prereleases_for, extended_explanation = find_names_to_relax(incompatibility)
- names_to_relax = names_to_unlock + names_to_allow_prereleases_for + names_to_allow_remote_specs_for
+ names_to_relax = names_to_unlock + names_to_allow_prereleases_for
if names_to_relax.any?
if names_to_unlock.any?
@@ -96,17 +85,11 @@ module Bundler
end
if names_to_allow_prereleases_for.any?
- Bundler.ui.debug "Found conflicts with dependencies with prereleases. Will retry considering prereleases for #{names_to_allow_prereleases_for.join(", ")}...", true
+ Bundler.ui.debug "Found conflicts with dependencies with prereleases. Will retrying considering prereleases for #{names_to_allow_prereleases_for.join(", ")}...", true
@base.include_prereleases(names_to_allow_prereleases_for)
end
- if names_to_allow_remote_specs_for.any?
- Bundler.ui.debug "Found conflicts with local versions of #{names_to_allow_remote_specs_for.join(", ")}. Will retry considering remote versions...", true
-
- @base.include_remote_specs(names_to_allow_remote_specs_for)
- end
-
root, logger = setup_solver
Bundler.ui.debug "Retrying resolution...", true
@@ -126,7 +109,6 @@ module Bundler
def find_names_to_relax(incompatibility)
names_to_unlock = []
names_to_allow_prereleases_for = []
- names_to_allow_remote_specs_for = []
extended_explanation = nil
while incompatibility.conflict?
@@ -139,10 +121,8 @@ 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
- elsif package.prefer_local? && @all_specs[name].any? {|s| !s.is_a?(StubSpecification) }
- names_to_allow_remote_specs_for << name
end
no_versions_incompat = [cause.incompatibility, cause.satisfier].find {|incompat| incompat.cause.is_a?(PubGrub::Incompatibility::NoVersions) }
@@ -152,7 +132,7 @@ module Bundler
end
end
- [names_to_unlock.uniq, names_to_allow_prereleases_for.uniq, names_to_allow_remote_specs_for.uniq, extended_explanation]
+ [names_to_unlock.uniq, names_to_allow_prereleases_for.uniq, extended_explanation]
end
def parse_dependency(package, dependency)
@@ -162,19 +142,13 @@ module Bundler
requirement_to_range(dependency)
end
- PubGrub::VersionConstraint.new(package, range: range)
+ PubGrub::VersionConstraint.new(package, :range => range)
end
def versions_for(package, range=VersionRange.any)
- versions = select_sorted_versions(package, range)
+ versions = range.select_versions(@sorted_versions[package])
- # Conditional avoids (among other things) calling
- # sort_versions_by_preferred with the root package
- if versions.size > 1
- sort_versions_by_preferred(package, versions)
- else
- versions
- end
+ sort_versions(package, versions)
end
def no_versions_incompatibility_for(package, unsatisfied_term)
@@ -184,7 +158,7 @@ module Bundler
constraint_string = constraint.constraint_string
requirements = constraint_string.split(" OR ").map {|req| Gem::Requirement.new(req.split(",")) }
- if name == "bundler" && bundler_pinned_to_current_version?
+ if name == "bundler"
custom_explanation = "the current Bundler version (#{Bundler::VERSION}) does not satisfy #{constraint}"
extended_explanation = bundler_not_found_message(requirements)
else
@@ -197,7 +171,7 @@ module Bundler
extended_explanation = other_specs_matching_message(specs_matching_other_platforms, label) if specs_matching_other_platforms.any?
end
- Incompatibility.new([unsatisfied_term], cause: cause, custom_explanation: custom_explanation, extended_explanation: extended_explanation)
+ Incompatibility.new([unsatisfied_term], :cause => cause, :custom_explanation => custom_explanation, :extended_explanation => extended_explanation)
end
def debug?
@@ -212,6 +186,11 @@ module Bundler
package_deps = @cached_dependencies[package]
sorted_versions = @sorted_versions[package]
package_deps[version].map do |dep_package, dep_constraint|
+ if package == dep_package
+ cause = PubGrub::Incompatibility::CircularDependency.new(dep_package, dep_constraint.constraint_string)
+ return [PubGrub::Incompatibility.new([PubGrub::Term.new(dep_constraint, true)], :cause => cause)]
+ end
+
low = high = sorted_versions.index(version)
# find version low such that all >= low share the same dep
@@ -236,9 +215,9 @@ module Bundler
sorted_versions[high]
end
- range = PubGrub::VersionRange.new(min: low, max: high, include_min: true)
+ range = PubGrub::VersionRange.new(:min => low, :max => high, :include_min => true)
- self_constraint = PubGrub::VersionConstraint.new(package, range: range)
+ self_constraint = PubGrub::VersionConstraint.new(package, :range => range)
dep_term = PubGrub::Term.new(dep_constraint, false)
self_term = PubGrub::Term.new(self_constraint, true)
@@ -247,71 +226,37 @@ module Bundler
"current #{dep_package} version is #{dep_constraint.constraint_string}"
end
- PubGrub::Incompatibility.new([self_term, dep_term], cause: :dependency, custom_explanation: custom_explanation)
+ PubGrub::Incompatibility.new([self_term, dep_term], :cause => :dependency, :custom_explanation => custom_explanation)
end
end
def all_versions_for(package)
name = package.name
- results = (@base[name] + filter_specs(@all_specs[name], package)).uniq {|spec| [spec.version.hash, spec.platform] }
-
- if name == "bundler" && !bundler_pinned_to_current_version?
- bundler_spec = Gem.loaded_specs["bundler"]
- results << bundler_spec if bundler_spec
- end
-
+ results = (@base[name] + filter_prereleases(@all_specs[name], package)).uniq {|spec| [spec.version.hash, spec.platform] }
locked_requirement = base_requirements[name]
results = filter_matching_specs(results, locked_requirement) if locked_requirement
- results.group_by(&:version).reduce([]) do |groups, (version, specs)|
- platform_specs = package.platform_specs(specs)
-
- # 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
+ versions = results.group_by(&:version).reduce([]) do |groups, (version, specs)|
+ 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)
- ruby_group = Resolver::SpecGroup.new(ruby_specs)
+ groups << Resolver::Candidate.new(version, :specs => ruby_specs) if ruby_specs.any?
- unless ruby_group.empty?
- platform_specs.each do |specs|
- ruby_group.merge(Resolver::SpecGroup.new(specs))
- end
-
- groups << Resolver::Candidate.new(version, group: ruby_group, priority: -1)
- next groups if package.force_ruby_platform?
- end
-
- platform_group = Resolver::SpecGroup.new(platform_specs.flatten.uniq)
- next groups if platform_group == ruby_group
+ next groups if platform_specs == ruby_specs
- groups << Resolver::Candidate.new(version, group: platform_group, priority: 1)
+ groups << Resolver::Candidate.new(version, :specs => platform_specs)
groups
end
+
+ sort_versions(package, versions)
end
def source_for(name)
@source_requirements[name] || @source_requirements[:default]
end
- def default_bundler_source
- @source_requirements[:default_bundler]
- end
-
- def bundler_pinned_to_current_version?
- !default_bundler_source.nil?
- end
-
def name_for_explicit_dependency_source
Bundler.default_gemfile.basename.to_s
rescue StandardError
@@ -331,21 +276,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)}"
@@ -356,56 +295,28 @@ module Bundler
private
- def filtered_versions_for(package)
- @gem_version_promoter.filter_versions(package, @all_versions[package])
- end
-
- def raise_all_versions_filtered_out!(package)
- level = @gem_version_promoter.level
- name = package.name
- locked_version = package.locked_version
- requirement = package.dependency
-
- raise GemNotFound,
- "#{name} is locked to #{locked_version}, while Gemfile is requesting #{requirement}. " \
- "--strict --#{level} was specified, but there are no #{level} level upgrades from #{locked_version} satisfying #{requirement}, so version solving has failed"
- end
-
def filter_matching_specs(specs, requirements)
Array(requirements).flat_map do |requirement|
specs.select {| spec| requirement_satisfied_by?(requirement, spec) }
end
end
- def filter_specs(specs, package)
- filter_remote_specs(filter_prereleases(specs, package), package)
- end
-
def filter_prereleases(specs, package)
- return specs unless package.ignores_prereleases? && specs.size > 1
+ return specs unless package.ignores_prereleases?
specs.reject {|s| s.version.prerelease? }
end
- def filter_remote_specs(specs, package)
- return specs unless package.prefer_local?
-
- specs.select {|s| s.is_a?(StubSpecification) }
- 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
- def sort_versions_by_preferred(package, versions)
- @gem_version_promoter.sort_versions(package, versions)
+ def sort_versions(package, versions)
+ if versions.size > 1
+ @gem_version_promoter.sort_versions(package, versions).reverse
+ else
+ versions
+ end
end
def repository_for(package)
@@ -422,22 +333,12 @@ module Bundler
next [dep_package, dep_constraint] if name == "bundler"
- dep_range = dep_constraint.range
- versions = select_sorted_versions(dep_package, dep_range)
- if versions.empty?
- if dep_package.ignores_prereleases? || dep_package.prefer_local?
- @all_versions.delete(dep_package)
- @sorted_versions.delete(dep_package)
- end
- dep_package.consider_prereleases! if dep_package.ignores_prereleases?
- dep_package.consider_remote_versions! if dep_package.prefer_local?
- versions = select_sorted_versions(dep_package, dep_range)
+ versions = versions_for(dep_package, dep_constraint.range)
+ if versions.empty? && dep_package.ignores_prereleases?
+ @sorted_versions.delete(dep_package)
+ dep_package.consider_prereleases!
+ versions = versions_for(dep_package, dep_constraint.range)
end
-
- if versions.empty? && select_all_versions(dep_package, dep_range).any?
- raise_all_versions_filtered_out!(dep_package)
- end
-
next [dep_package, dep_constraint] unless versions.empty?
next unless dep_package.current_platform?
@@ -446,14 +347,6 @@ module Bundler
end.compact.to_h
end
- def select_sorted_versions(package, range)
- range.select_versions(@sorted_versions[package])
- end
-
- def select_all_versions(package, range)
- range.select_versions(@all_versions[package])
- end
-
def other_specs_matching_message(specs, requirement)
message = String.new("The source contains the following gems matching '#{requirement}':\n")
message << specs.map {|s| " * #{s.full_name}" }.join("\n")
@@ -462,26 +355,26 @@ module Bundler
def requirement_to_range(requirement)
ranges = requirement.requirements.map do |(op, version)|
- ver = Resolver::Candidate.new(version, priority: -1)
- platform_ver = Resolver::Candidate.new(version, priority: 1)
+ ver = Resolver::Candidate.new(version).generic!
+ platform_ver = Resolver::Candidate.new(version).platform_specific!
case op
when "~>"
name = "~> #{ver}"
bump = Resolver::Candidate.new(version.bump.to_s + ".A")
- PubGrub::VersionRange.new(name: name, min: ver, max: bump, include_min: true)
+ PubGrub::VersionRange.new(:name => name, :min => ver, :max => bump, :include_min => true)
when ">"
- PubGrub::VersionRange.new(min: platform_ver)
+ PubGrub::VersionRange.new(:min => platform_ver)
when ">="
- PubGrub::VersionRange.new(min: ver, include_min: true)
+ PubGrub::VersionRange.new(:min => ver, :include_min => true)
when "<"
- PubGrub::VersionRange.new(max: ver)
+ PubGrub::VersionRange.new(:max => ver)
when "<="
- PubGrub::VersionRange.new(max: platform_ver, include_max: true)
+ PubGrub::VersionRange.new(:max => platform_ver, :include_max => true)
when "="
- PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true)
+ PubGrub::VersionRange.new(:min => ver, :max => platform_ver, :include_min => true, :include_max => true)
when "!="
- PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true).invert
+ PubGrub::VersionRange.new(:min => ver, :max => platform_ver, :include_min => true, :include_max => true).invert
else
raise "bad version specifier: #{op}"
end
@@ -508,7 +401,7 @@ module Bundler
end
def bundler_not_found_message(conflict_dependencies)
- candidate_specs = filter_matching_specs(default_bundler_source.specs.search("bundler"), conflict_dependencies)
+ candidate_specs = filter_matching_specs(source_for(:default_bundler).specs.search("bundler"), conflict_dependencies)
if candidate_specs.any?
target_version = candidate_specs.last.version
diff --git a/lib/bundler/resolver/base.rb b/lib/bundler/resolver/base.rb
index 3f2436672a..6921c047a7 100644
--- a/lib/bundler/resolver/base.rb
+++ b/lib/bundler/resolver/base.rb
@@ -24,22 +24,20 @@ module Bundler
name = dep.name
- @packages[name] = Package.new(name, dep_platforms, **options.merge(dependency: dep))
+ @packages[name] = Package.new(name, dep_platforms, **options.merge(:dependency => dep))
dep
end.compact
end
- def specs_compatible_with(result)
- @base.specs_compatible_with(result)
- end
-
def [](name)
@base[name]
end
def delete(specs)
- @base.delete(specs)
+ specs.each do |spec|
+ @base.delete(spec)
+ end
end
def get_package(name)
@@ -51,18 +49,10 @@ module Bundler
end
def unlock_names(names)
- indirect_pins = indirect_pins(names)
-
- if indirect_pins.any?
- loosen_names(indirect_pins)
- else
- pins = pins(names)
-
- if pins.any?
- loosen_names(pins)
- else
- unrestrict_names(names)
- end
+ names.each do |name|
+ @base.delete_by_name(name)
+
+ @base_requirements.delete(name)
end
end
@@ -72,38 +62,8 @@ module Bundler
end
end
- def include_remote_specs(names)
- names.each do |name|
- get_package(name).consider_remote_versions!
- end
- end
-
private
- def indirect_pins(names)
- names.select {|name| @base_requirements[name].exact? && @requirements.none? {|dep| dep.name == name } }
- end
-
- def pins(names)
- names.select {|name| @base_requirements[name].exact? }
- end
-
- def loosen_names(names)
- names.each do |name|
- version = @base_requirements[name].requirements.first[1]
-
- @base_requirements[name] = Gem::Requirement.new(">= #{version}")
-
- @base.delete_by_name(name)
- end
- end
-
- def unrestrict_names(names)
- names.each do |name|
- @base_requirements.delete(name)
- end
- end
-
def build_base_requirements
base_requirements = {}
@base.each do |ls|
diff --git a/lib/bundler/resolver/candidate.rb b/lib/bundler/resolver/candidate.rb
index f593fc5d61..e695ef08ee 100644
--- a/lib/bundler/resolver/candidate.rb
+++ b/lib/bundler/resolver/candidate.rb
@@ -15,7 +15,7 @@ module Bundler
# considered separately.
#
# Some candidates may also keep some information explicitly about the
- # package they refer to. These candidates are referred to as "canonical" and
+ # package the refer to. These candidates are referred to as "canonical" and
# are used when materializing resolution results back into RubyGems
# specifications that can be installed, written to lock files, and so on.
#
@@ -24,10 +24,10 @@ module Bundler
attr_reader :version
- def initialize(version, group: nil, priority: -1)
- @spec_group = group || SpecGroup.new([])
+ def initialize(version, specs: [])
+ @spec_group = Resolver::SpecGroup.new(specs)
@version = Gem::Version.new(version)
- @priority = priority
+ @ruby_only = specs.map(&:platform).uniq == [Gem::Platform::RUBY]
end
def dependencies
@@ -40,6 +40,18 @@ module Bundler
@spec_group.to_specs(package.force_ruby_platform?)
end
+ def generic!
+ @ruby_only = true
+
+ self
+ end
+
+ def platform_specific!
+ @ruby_only = false
+
+ self
+ end
+
def prerelease?
@version.prerelease?
end
@@ -49,7 +61,7 @@ module Bundler
end
def sort_obj
- [@version, @priority]
+ [@version, @ruby_only ? -1 : 1]
end
def <=>(other)
diff --git a/lib/bundler/resolver/incompatibility.rb b/lib/bundler/resolver/incompatibility.rb
index 4ac1b2e1ea..c61151fbeb 100644
--- a/lib/bundler/resolver/incompatibility.rb
+++ b/lib/bundler/resolver/incompatibility.rb
@@ -8,7 +8,7 @@ module Bundler
def initialize(terms, cause:, custom_explanation: nil, extended_explanation: nil)
@extended_explanation = extended_explanation
- super(terms, cause: cause, custom_explanation: custom_explanation)
+ super(terms, :cause => cause, :custom_explanation => custom_explanation)
end
end
end
diff --git a/lib/bundler/resolver/package.rb b/lib/bundler/resolver/package.rb
index 5aecc12d05..7499a75006 100644
--- a/lib/bundler/resolver/package.rb
+++ b/lib/bundler/resolver/package.rb
@@ -15,19 +15,13 @@ module Bundler
class Package
attr_reader :name, :platforms, :dependency, :locked_version
- def initialize(name, platforms, locked_specs:, unlock:, prerelease: false, prefer_local: false, dependency: nil)
+ def initialize(name, platforms, locked_specs:, unlock:, prerelease: false, dependency: nil)
@name = name
@platforms = platforms
@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
- @prefer_local = prefer_local
- end
-
- def platform_specs(specs)
- platforms.map {|platform| GemHelpers.select_best_platform_match(specs, platform, prefer_locked: !unlock?) }
end
def to_s
@@ -38,10 +32,6 @@ module Bundler
false
end
- def top_level?
- @top_level
- end
-
def meta?
@name.end_with?("\0")
end
@@ -70,14 +60,6 @@ module Bundler
@prerelease = :consider_last
end
- def prefer_local?
- @prefer_local
- end
-
- def consider_remote_versions!
- @prefer_local = false
- end
-
def force_ruby_platform?
@dependency.force_ruby_platform
end
diff --git a/lib/bundler/resolver/spec_group.rb b/lib/bundler/resolver/spec_group.rb
index f950df6eda..b44c19a73f 100644
--- a/lib/bundler/resolver/spec_group.rb
+++ b/lib/bundler/resolver/spec_group.rb
@@ -3,8 +3,6 @@
module Bundler
class Resolver
class SpecGroup
- attr_reader :specs
-
def initialize(specs)
@specs = specs
end
@@ -27,8 +25,9 @@ module Bundler
def to_specs(force_ruby_platform)
@specs.map do |s|
- lazy_spec = LazySpecification.from_spec(s)
+ lazy_spec = LazySpecification.new(name, version, s.platform, source)
lazy_spec.force_ruby_platform = force_ruby_platform
+ lazy_spec.dependencies.replace s.dependencies
lazy_spec
end
end
@@ -40,33 +39,17 @@ module Bundler
def dependencies
@dependencies ||= @specs.map do |spec|
__dependencies(spec) + metadata_dependencies(spec)
- end.flatten.uniq.sort
- end
-
- def ==(other)
- sorted_spec_names == other.sorted_spec_names
- end
-
- def merge(other)
- return false unless equivalent?(other)
-
- @specs |= other.specs
-
- true
+ end.flatten.uniq
end
protected
def sorted_spec_names
- @specs.map(&:full_name).sort
+ @sorted_spec_names ||= @specs.map(&:full_name).sort
end
private
- def equivalent?(other)
- name == other.name && version == other.version && source == other.source && dependencies == other.dependencies
- end
-
def exemplary_spec
@specs.first
end
@@ -81,6 +64,8 @@ module Bundler
end
def metadata_dependencies(spec)
+ return [] if spec.is_a?(LazySpecification)
+
[
metadata_dependency("Ruby", spec.required_ruby_version),
metadata_dependency("RubyGems", spec.required_rubygems_version),
diff --git a/lib/bundler/retry.rb b/lib/bundler/retry.rb
index 090cb7e2ca..2415ade200 100644
--- a/lib/bundler/retry.rb
+++ b/lib/bundler/retry.rb
@@ -50,13 +50,13 @@ module Bundler
end
return true unless name
Bundler.ui.info "" unless Bundler.ui.debug? # Add new line in case dots preceded this
- Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", true
+ Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", Bundler.ui.debug?
end
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 fb4b79c4df..3b3a0583a5 100644
--- a/lib/bundler/ruby_dsl.rb
+++ b/lib/bundler/ruby_dsl.rb
@@ -3,51 +3,16 @@
module Bundler
module RubyDsl
def ruby(*ruby_version)
- options = ruby_version.pop if ruby_version.last.is_a?(Hash)
+ options = ruby_version.last.is_a?(Hash) ? ruby_version.pop : {}
ruby_version.flatten!
+ raise GemfileError, "Please define :engine_version" if options[:engine] && options[:engine_version].nil?
+ raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil?
- if options
- patchlevel = options[:patchlevel]
- engine = options[:engine]
- engine_version = options[:engine_version]
-
- raise GemfileError, "Please define :engine_version" if engine && engine_version.nil?
- raise GemfileError, "Please define :engine" if engine_version && 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])
- end
-
- if engine == "ruby" && engine_version && ruby_version != Array(engine_version)
- raise GemfileEvalError, "ruby_version must match the :engine_version for MRI"
- end
- end
-
- @ruby_version = RubyVersion.new(ruby_version, patchlevel, engine, 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
- #
- # Loads the file relative to the dirname of the Gemfile itself.
- def normalize_ruby_file(filename)
- file_content = Bundler.read_file(gemfile.dirname.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
+ if options[:engine] == "ruby" && options[:engine_version] &&
+ ruby_version != Array(options[:engine_version])
+ raise GemfileEvalError, "ruby_version must match the :engine_version for MRI"
end
+ @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version])
end
end
end
diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb
index 0ed5cbc6ca..9161c6afde 100644
--- a/lib/bundler/ruby_version.rb
+++ b/lib/bundler/ruby_version.rb
@@ -23,19 +23,13 @@ module Bundler
# specified must match the version.
@versions = Array(versions).map do |v|
- normalized_v = normalize_version(v)
-
- unless Gem::Requirement::PATTERN.match?(normalized_v)
- raise InvalidArgumentError, "#{v} is not a valid requirement on the Ruby version"
- end
-
- op, v = Gem::Requirement.parse(normalized_v)
+ op, v = Gem::Requirement.parse(v)
op == "=" ? v.to_s : "#{op} #{v}"
end
@gem_version = Gem::Requirement.create(@versions.first).requirements.first.last
- @input_engine = engine&.to_s
- @engine = engine&.to_s || "ruby"
+ @input_engine = engine && engine.to_s
+ @engine = engine && engine.to_s || "ruby"
@engine_versions = (engine_version && Array(engine_version)) || @versions
@engine_gem_version = Gem::Requirement.create(@engine_versions.first).requirements.first.last
@patchlevel = patchlevel || (@gem_version.prerelease? ? "-1" : nil)
@@ -55,7 +49,7 @@ module Bundler
(\d+\.\d+\.\d+(?:\.\S+)?) # ruby version
(?:p(-?\d+))? # optional patchlevel
(?:\s\((\S+)\s(.+)\))? # optional engine info
- /xo
+ /xo.freeze
# Returns a RubyVersion from the given string.
# @param [String] the version string to match.
@@ -113,18 +107,11 @@ module Bundler
ruby_engine_version = RUBY_ENGINE == "ruby" ? ruby_version : RUBY_ENGINE_VERSION.dup
patchlevel = RUBY_PATCHLEVEL.to_s
- @system ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version)
+ @ruby_version ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version)
end
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 56d18f28fd..0252e1a81a 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
-require "rubygems" unless defined?(Gem)
+require "pathname"
+
+require "rubygems/specification"
# We can't let `Gem::Source` be autoloaded in the `Gem::Specification#source`
# redefinition below, so we need to load it upfront. The reason is that if
@@ -13,6 +15,10 @@ require "rubygems" unless defined?(Gem)
# `Gem::Source` from the redefined `Gem::Specification#source`.
require "rubygems/source"
+require_relative "match_metadata"
+require_relative "force_platform"
+require_relative "match_platform"
+
# Cherry-pick fixes to `Gem.ruby_version` to be useful for modern Bundler
# versions and ignore patchlevels
# (https://github.com/rubygems/rubygems/pull/5472,
@@ -23,59 +29,7 @@ unless Gem.ruby_version.to_s == RUBY_VERSION || RUBY_PATCHLEVEL == -1
end
module Gem
- # Can be removed once RubyGems 3.5.11 support is dropped
- unless Gem.respond_to?(:freebsd_platform?)
- def self.freebsd_platform?
- RbConfig::CONFIG["host_os"].to_s.include?("bsd")
- end
- end
-
- # Can be removed once RubyGems 3.5.18 support is dropped
- unless Gem.respond_to?(:open_file_with_lock)
- class << self
- remove_method :open_file_with_flock if Gem.respond_to?(:open_file_with_flock)
-
- def open_file_with_flock(path, &block)
- # read-write mode is used rather than read-only in order to support NFS
- mode = IO::RDWR | IO::APPEND | IO::CREAT | IO::BINARY
- mode |= IO::SHARE_DELETE if IO.const_defined?(:SHARE_DELETE)
-
- File.open(path, mode) do |io|
- begin
- io.flock(File::LOCK_EX)
- rescue Errno::ENOSYS, Errno::ENOTSUP
- end
- yield io
- end
- end
-
- def open_file_with_lock(path, &block)
- file_lock = "#{path}.lock"
- open_file_with_flock(file_lock, &block)
- ensure
- FileUtils.rm_f file_lock
- end
- end
- end
-
- require "rubygems/specification"
-
- # Can be removed once RubyGems 3.5.14 support is dropped
- VALIDATES_FOR_RESOLUTION = Specification.new.respond_to?(:validate_for_resolution).freeze
-
- # Can be removed once RubyGems 3.3.15 support is dropped
- FLATTENS_REQUIRED_PATHS = Specification.new.respond_to?(:flatten_require_paths).freeze
-
class Specification
- # Can be removed once RubyGems 3.5.15 support is dropped
- correct_array_attributes = @@default_value.select {|_k,v| v.is_a?(Array) }.keys
- unless @@array_attributes == correct_array_attributes
- @@array_attributes = correct_array_attributes # rubocop:disable Style/ClassVars
- end
-
- require_relative "match_metadata"
- require_relative "match_platform"
-
include ::Bundler::MatchMetadata
include ::Bundler::MatchPlatform
@@ -92,7 +46,7 @@ module Gem
def full_gem_path
if source.respond_to?(:root)
- File.expand_path(File.dirname(loaded_from), source.root)
+ Pathname.new(loaded_from).dirname.expand_path(source.root).to_s.tap {|x| x.untaint if RUBY_VERSION < "2.7" }
else
rg_full_gem_path
end
@@ -112,9 +66,7 @@ module Gem
alias_method :rg_extension_dir, :extension_dir
def extension_dir
- # following instance variable is already used in original method
- # and that is the reason to prefix it with bundler_ and add rubocop exception
- @bundler_extension_dir ||= if source.respond_to?(:extension_dir_name) # rubocop:disable Naming/MemoizedInstanceVariableName
+ @bundler_extension_dir ||= if source.respond_to?(:extension_dir_name)
unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-")
File.expand_path(File.join(extensions_dir, unique_extension_dir))
else
@@ -122,7 +74,7 @@ module Gem
end
end
- remove_method :gem_dir
+ remove_method :gem_dir if instance_methods(false).include?(:gem_dir)
def gem_dir
full_gem_path
end
@@ -163,39 +115,23 @@ module Gem
gemfile
end
- def nondevelopment_dependencies
- dependencies - development_dependencies
- end
-
- def deleted_gem?
- !default_gem? && !File.directory?(full_gem_path)
- end
+ # Backfill missing YAML require when not defined. Fixed since 3.1.0.pre1.
+ module YamlBackfiller
+ def to_yaml(opts = {})
+ Gem.load_yaml unless defined?(::YAML)
- unless VALIDATES_FOR_RESOLUTION
- def validate_for_resolution
- SpecificationPolicy.new(self).validate_for_resolution
+ super(opts)
end
end
- unless FLATTENS_REQUIRED_PATHS
- def flatten_require_paths
- return unless raw_require_paths.first.is_a?(Array)
+ prepend YamlBackfiller
- warn "#{name} #{version} includes a gemspec with `require_paths` set to an array of arrays. Newer versions of this gem might've already fixed this"
- raw_require_paths.flatten!
- end
-
- class << self
- module RequirePathFlattener
- def from_yaml(input)
- spec = super(input)
- spec.flatten_require_paths
- spec
- end
- end
+ def nondevelopment_dependencies
+ dependencies - development_dependencies
+ end
- prepend RequirePathFlattener
- end
+ def deleted_gem?
+ !default_gem? && !File.directory?(full_gem_path)
end
private
@@ -217,47 +153,29 @@ module Gem
end
end
- unless VALIDATES_FOR_RESOLUTION
- class SpecificationPolicy
- def validate_for_resolution
- validate_required!
- end
- end
- end
-
- module BetterPermissionError
- def data
- super
- rescue Errno::EACCES
- raise Bundler::PermissionError.new(loaded_from, :read)
- end
- end
-
- require "rubygems/stub_specification"
-
- class StubSpecification
- prepend BetterPermissionError
- end
-
class Dependency
- require_relative "force_platform"
-
include ::Bundler::ForcePlatform
- attr_reader :force_ruby_platform
-
attr_accessor :source, :groups
alias_method :eql?, :==
- unless method_defined?(:encode_with, false)
- def encode_with(coder)
- [:@name, :@requirement, :@type, :@prerelease, :@version_requirements].each do |ivar|
- coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar)
- end
+ def force_ruby_platform
+ return @force_ruby_platform if defined?(@force_ruby_platform) && !@force_ruby_platform.nil?
+
+ @force_ruby_platform = default_force_ruby_platform
+ end
+
+ def encode_with(coder)
+ to_yaml_properties.each do |ivar|
+ coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar)
end
end
+ def to_yaml_properties
+ instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) }
+ end
+
def to_lock
out = String.new(" #{name}")
unless requirement.none?
@@ -266,19 +184,39 @@ module Gem
end
out
end
+ end
+
+ # comparison is done order independently since rubygems 3.2.0.rc.2
+ unless Gem::Requirement.new("> 1", "< 2") == Gem::Requirement.new("< 2", "> 1")
+ class Requirement
+ module OrderIndependentComparison
+ def ==(other)
+ return unless Gem::Requirement === other
- if Gem.rubygems_version < Gem::Version.new("3.5.22")
- module FilterIgnoredSpecs
- def matching_specs(platform_only = false)
- super.reject(&:ignored?)
+ if _requirements_sorted? && other._requirements_sorted?
+ super
+ else
+ _with_sorted_requirements == other._with_sorted_requirements
+ end
+ end
+
+ protected
+
+ def _requirements_sorted?
+ return @_are_requirements_sorted if defined?(@_are_requirements_sorted)
+ strings = as_list
+ @_are_requirements_sorted = strings == strings.sort
+ end
+
+ def _with_sorted_requirements
+ @_with_sorted_requirements ||= _requirements_sorted? ? self : self.class.new(as_list.sort)
end
end
- prepend FilterIgnoredSpecs
+ prepend OrderIndependentComparison
end
end
- # Requirements using lambda operator differentiate trailing zeros since rubygems 3.2.6
if Gem::Requirement.new("~> 2.0").hash == Gem::Requirement.new("~> 2.0.0").hash
class Requirement
module CorrectHashForLambdaOperator
@@ -320,7 +258,7 @@ module Gem
# cpu
([nil,"universal"].include?(@cpu) || [nil, "universal"].include?(other.cpu) || @cpu == other.cpu ||
- (@cpu == "arm" && other.cpu.start_with?("armv"))) &&
+ (@cpu == "arm" && other.cpu.start_with?("arm"))) &&
# os
@os == other.os &&
@@ -380,7 +318,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"
@@ -393,63 +331,23 @@ 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
-
- # Can be removed once RubyGems 3.5.22 support is dropped
- unless new.respond_to?(:ignored?)
- def ignored?
- return @ignored unless @ignored.nil?
-
- @ignored = missing_extensions?
- end
- end
end
- require "rubygems/name_tuple"
+ require "rubygems/util"
- class NameTuple
- # Versions of RubyGems before about 3.5.0 don't to_s the platform.
- unless Gem::NameTuple.new("a", Gem::Version.new("1"), Gem::Platform.new("x86_64-linux")).platform.is_a?(String)
- alias_method :initialize_with_platform, :initialize
-
- def initialize(name, version, platform=Gem::Platform::RUBY)
- if Gem::Platform === platform
- initialize_with_platform(name, version, platform.to_s)
- else
- initialize_with_platform(name, version, platform)
- end
- end
+ Util.singleton_class.module_eval do
+ if Util.singleton_methods.include?(:glob_files_in_dir) # since 3.0.0.beta.2
+ remove_method :glob_files_in_dir
end
- def lock_name
- if platform == Gem::Platform::RUBY
- "#{name} (#{version})"
- else
- "#{name} (#{version}-#{platform})"
- end
- end
- end
-
- unless Gem.rubygems_version >= Gem::Version.new("3.5.19")
- class Resolver::ActivationRequest
- remove_method :installed?
-
- def installed?
- case @spec
- when Gem::Resolver::VendorSpecification then
- true
- else
- this_spec = full_spec
-
- Gem::Specification.any? do |s|
- s == this_spec && s.base_dir == this_spec.base_dir
- end
- end
- end
+ def glob_files_in_dir(glob, base_path)
+ Dir.glob(glob, :base => base_path).map! {|f| File.expand_path(f, base_path) }
end
end
end
diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb
index 62756680e7..38035a00ac 100644
--- a/lib/bundler/rubygems_gem_installer.rb
+++ b/lib/bundler/rubygems_gem_installer.rb
@@ -20,7 +20,7 @@ module Bundler
strict_rm_rf spec.extension_dir
SharedHelpers.filesystem_access(gem_dir, :create) do
- FileUtils.mkdir_p gem_dir, mode: 0o755
+ FileUtils.mkdir_p gem_dir, :mode => 0o755
end
extract_files
@@ -29,10 +29,7 @@ module Bundler
write_build_info_file
run_post_build_hooks
- SharedHelpers.filesystem_access(bin_dir, :write) do
- generate_bin
- end
-
+ generate_bin
generate_plugins
write_spec
@@ -48,24 +45,6 @@ module Bundler
spec
end
- if Bundler.rubygems.provides?("< 3.5")
- 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
- end
-
- def ensure_writable_dir(dir)
- 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)
@@ -81,24 +60,8 @@ module Bundler
end
end
- if Bundler.rubygems.provides?("< 3.5.19")
- def generate_bin_script(filename, bindir)
- bin_script_path = File.join bindir, formatted_program_filename(filename)
-
- Gem.open_file_with_lock(bin_script_path) do
- 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.write app_script_text(filename)
- file.chmod(options[:prog_mode] || 0o755)
- end
- end
-
- verbose bin_script_path
-
- generate_windows_script filename, bindir
- end
+ def pre_install_checks
+ super && validate_bundler_checksum(options[:bundler_expected_checksum])
end
def build_extensions
@@ -135,10 +98,6 @@ module Bundler
end
end
- def gem_checksum
- Checksum.from_gem_package(@package)
- end
-
private
def prepare_extension_build(extension_dir)
@@ -149,22 +108,64 @@ module Bundler
end
def strict_rm_rf(dir)
- return unless File.exist?(dir)
- return if Dir.empty?(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(spec.full_name, dir)
+ 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 5944ab86e0..3857948511 100644
--- a/lib/bundler/rubygems_integration.rb
+++ b/lib/bundler/rubygems_integration.rb
@@ -4,12 +4,17 @@ require "rubygems" unless defined?(Gem)
module Bundler
class RubygemsIntegration
- require "monitor"
+ if defined?(Gem::Ext::Builder::CHDIR_MONITOR)
+ EXT_LOCK = Gem::Ext::Builder::CHDIR_MONITOR
+ else
+ require "monitor"
- EXT_LOCK = Monitor.new
+ EXT_LOCK = Monitor.new
+ end
def initialize
@replaced_methods = {}
+ backport_ext_builder_monitor
end
def version
@@ -38,6 +43,18 @@ module Bundler
Gem.loaded_specs[name]
end
+ def add_to_load_path(paths)
+ return Gem.add_to_load_path(*paths) if Gem.respond_to?(:add_to_load_path)
+
+ if insert_index = Gem.load_path_insert_index
+ # Gem directories must come after -I and ENV['RUBYLIB']
+ $LOAD_PATH.insert(insert_index, *paths)
+ else
+ # We are probably testing in core, -I and RUBYLIB don't apply
+ $LOAD_PATH.unshift(*paths)
+ end
+ end
+
def mark_loaded(spec)
if spec.respond_to?(:activated=)
current = Gem.loaded_specs[spec.name]
@@ -48,7 +65,7 @@ module Bundler
end
def validate(spec)
- Bundler.ui.silence { spec.validate_for_resolution }
+ Bundler.ui.silence { spec.validate(false) }
rescue Gem::InvalidSpecificationException => e
error_message = "The gemspec at #{spec.loaded_from} is not valid. Please fix this gemspec.\n" \
"The validation error was '#{e.message}'\n"
@@ -57,6 +74,28 @@ module Bundler
nil
end
+ def set_installed_by_version(spec, installed_by_version = Gem::VERSION)
+ return unless spec.respond_to?(:installed_by_version=)
+ spec.installed_by_version = Gem::Version.create(installed_by_version)
+ end
+
+ def spec_missing_extensions?(spec, default = true)
+ return spec.missing_extensions? if spec.respond_to?(:missing_extensions?)
+
+ return false if spec.default_gem?
+ return false if spec.extensions.empty?
+
+ default
+ end
+
+ def spec_matches_for_glob(spec, glob)
+ return spec.matches_for_glob(glob) if spec.respond_to?(:matches_for_glob)
+
+ spec.load_paths.map do |lp|
+ Dir["#{lp}/#{glob}#{suffix_pattern}"]
+ end.flatten(1)
+ end
+
def stub_set_spec(stub, spec)
stub.instance_variable_set(:@spec, spec)
end
@@ -77,6 +116,16 @@ module Bundler
Gem::Util.inflate(obj)
end
+ def correct_for_windows_path(path)
+ if Gem::Util.respond_to?(:correct_for_windows_path)
+ Gem::Util.correct_for_windows_path(path)
+ elsif path[0].chr == "/" && path[1].chr =~ /[a-z]/i && path[2].chr == ":"
+ path[1..-1]
+ else
+ path
+ end
+ end
+
def gem_dir
Gem.dir
end
@@ -112,7 +161,7 @@ module Bundler
def spec_cache_dirs
@spec_cache_dirs ||= begin
dirs = gem_path.map {|dir| File.join(dir, "specifications") }
- dirs << Gem.spec_cache_dir
+ dirs << Gem.spec_cache_dir if Gem.respond_to?(:spec_cache_dir) # Not in RubyGems 2.0.3 or earlier
dirs.uniq.select {|dir| File.directory? dir }
end
end
@@ -134,6 +183,18 @@ module Bundler
loaded_gem_paths.flatten
end
+ def load_plugins
+ Gem.load_plugins if Gem.respond_to?(:load_plugins)
+ end
+
+ def load_plugin_files(files)
+ Gem.load_plugin_files(files) if Gem.respond_to?(:load_plugin_files)
+ end
+
+ def load_env_plugins
+ Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins)
+ end
+
def ui=(obj)
Gem::DefaultUserInteraction.ui = obj
end
@@ -169,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
@@ -178,11 +240,14 @@ module Bundler
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_locations(1, 1).first.path))
+ if executables && executables.include?(File.basename(caller.first.split(":").first))
break
end
@@ -293,14 +358,6 @@ module Bundler
def replace_entrypoints(specs)
specs_by_name = add_default_gems_to(specs)
- reverse_rubygems_kernel_mixin
- begin
- # bundled_gems only provide with Ruby 3.3 or later
- require "bundled_gems"
- rescue LoadError
- else
- Gem::BUNDLED_GEMS.replace_require(specs) if Gem::BUNDLED_GEMS.respond_to?(:replace_require)
- end
replace_gem(specs, specs_by_name)
stub_rubygems(specs)
replace_bin_path(specs_by_name)
@@ -390,28 +447,30 @@ module Bundler
Gem::Specification.all = specs
end
- def fetch_specs(remote, name, fetcher)
+ def fetch_specs(remote, name)
require "rubygems/remote_fetcher"
path = remote.uri.to_s + "#{name}.#{Gem.marshal_version}.gz"
+ 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.load_marshal(string)
rescue Gem::RemoteFetcher::FetchError
# it's okay for prerelease to fail
raise unless name == "prerelease_specs"
end
- def fetch_all_remote_specs(remote, gem_remote_fetcher)
- specs = fetch_specs(remote, "specs", gem_remote_fetcher)
- pres = fetch_specs(remote, "prerelease_specs", gem_remote_fetcher) || []
+ def fetch_all_remote_specs(remote)
+ specs = fetch_specs(remote, "specs")
+ pres = fetch_specs(remote, "prerelease_specs") || []
specs.concat(pres)
end
- def download_gem(spec, uri, cache_dir, fetcher)
+ def download_gem(spec, uri, cache_dir)
require "rubygems/remote_fetcher"
uri = Bundler.settings.mirror_for(uri)
+ fetcher = gem_remote_fetcher
+ fetcher.headers = { "X-Gemfile-Source" => spec.remote.original_uri.to_s } if spec.remote.original_uri
Bundler::Retry.new("download gem from #{uri}").attempts do
gem_file_name = spec.file_name
local_gem_path = File.join cache_dir, gem_file_name
@@ -419,6 +478,7 @@ module Bundler
begin
remote_gem_path = uri + "gems/#{gem_file_name}"
+ remote_gem_path = remote_gem_path.to_s if provides?("< 3.2.0.rc.1")
SharedHelpers.filesystem_access(local_gem_path) do
fetcher.cache_update_path remote_gem_path, local_gem_path
@@ -437,6 +497,12 @@ module Bundler
raise Bundler::HTTPError, "Could not download gem from #{uri} due to underlying error <#{e.message}>"
end
+ def gem_remote_fetcher
+ require "rubygems/remote_fetcher"
+ proxy = Gem.configuration[:http_proxy]
+ Gem::RemoteFetcher.new(proxy)
+ end
+
def build(spec, skip_validation = false)
require "rubygems/package"
Gem::Package.build(spec, skip_validation)
@@ -447,22 +513,27 @@ module Bundler
end
def all_specs
- SharedHelpers.major_deprecation 2, "Bundler.rubygems.all_specs has been removed in favor of Bundler.rubygems.installed_specs"
-
Gem::Specification.stubs.map do |stub|
StubSpecification.from_stub(stub)
end
end
- def installed_specs
- Gem::Specification.stubs.reject(&:default_gem?).map do |stub|
- StubSpecification.from_stub(stub)
- end
- end
+ def backport_ext_builder_monitor
+ # So we can avoid requiring "rubygems/ext" in its entirety
+ Gem.module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ module Ext
+ end
+ RUBY
- def default_specs
- Gem::Specification.default_stubs.map do |stub|
- StubSpecification.from_stub(stub)
+ require "rubygems/ext/builder"
+
+ Gem::Ext::Builder.class_eval do
+ unless const_defined?(:CHDIR_MONITOR)
+ const_set(:CHDIR_MONITOR, EXT_LOCK)
+ end
+
+ remove_const(:CHDIR_MUTEX) if const_defined?(:CHDIR_MUTEX)
+ const_set(:CHDIR_MUTEX, const_get(:CHDIR_MONITOR))
end
end
@@ -474,8 +545,14 @@ module Bundler
Gem::Specification.stubs_for(name).map(&:to_spec)
end
- def default_stubs
- Gem::Specification.default_stubs("*.gemspec")
+ if Gem::Specification.respond_to?(:default_stubs)
+ def default_stubs
+ Gem::Specification.default_stubs("*.gemspec")
+ end
+ else
+ def default_stubs
+ Gem::Specification.send(:default_stubs, "*.gemspec")
+ end
end
end
diff --git a/lib/bundler/runtime.rb b/lib/bundler/runtime.rb
index 5f7dd7a848..bd38353d3c 100644
--- a/lib/bundler/runtime.rb
+++ b/lib/bundler/runtime.rb
@@ -10,7 +10,7 @@ module Bundler
end
def setup(*groups)
- @definition.ensure_equivalent_gemfile_and_lockfile
+ @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen_bundle?
# Has to happen first
clean_load_path
@@ -28,11 +28,11 @@ module Bundler
spec.load_paths.reject {|path| $LOAD_PATH.include?(path) }
end.reverse.flatten
- Gem.add_to_load_path(*load_paths)
+ Bundler.rubygems.add_to_load_path(load_paths)
setup_manpath
- lock(preserve_unknown_sections: true)
+ lock(:preserve_unknown_sections => true)
self
end
@@ -94,8 +94,8 @@ module Bundler
definition_method :requires
def lock(opts = {})
- return if @definition.no_resolve_needed?
- @definition.lock(opts[:preserve_unknown_sections])
+ return if @definition.nothing_changed? && !@definition.unlocking?
+ @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections])
end
alias_method :gems, :specs
@@ -128,6 +128,11 @@ module Bundler
spec.source.cache(spec, custom_path) if spec.source.respond_to?(:cache)
end
+ Dir[cache_path.join("*/.git")].each do |git_dir|
+ FileUtils.rm_rf(git_dir)
+ FileUtils.touch(File.expand_path("../.bundlecache", git_dir))
+ end
+
prune_cache(cache_path) unless Bundler.settings[:no_prune]
end
diff --git a/lib/bundler/safe_marshal.rb b/lib/bundler/safe_marshal.rb
deleted file mode 100644
index 50aa0f60a6..0000000000
--- a/lib/bundler/safe_marshal.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- module SafeMarshal
- ALLOWED_CLASSES = [
- Array,
- FalseClass,
- Gem::Specification,
- Gem::Version,
- Hash,
- String,
- Symbol,
- Time,
- TrueClass,
- ].freeze
-
- ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed."
-
- PROC = proc do |object|
- object.tap do
- unless ALLOWED_CLASSES.include?(object.class)
- raise TypeError, format(ERROR, object.class, ALLOWED_CLASSES.join(", "))
- end
- end
- end
-
- def self.proc
- PROC
- end
- end
-end
diff --git a/lib/bundler/self_manager.rb b/lib/bundler/self_manager.rb
index a6d93f20ff..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)
@@ -70,23 +64,8 @@ module Bundler
configured_gem_home = ENV["GEM_HOME"]
configured_gem_path = ENV["GEM_PATH"]
- # Bundler specs need some stuff to be required before Bundler starts
- # running, for example, for faking the compact index API. However, these
- # flags are lost when we reexec to a different version of Bundler. In the
- # future, we may be able to properly reconstruct the original Ruby
- # invocation (see https://bugs.ruby-lang.org/issues/6648), but for now
- # there's no way to do it, so we need to be explicit about how to re-exec.
- # This may be a feature end users request at some point, but maybe by that
- # time, we have builtin tools to do. So for now, we use an undocumented
- # ENV variable only for our specs.
- bundler_spec_original_cmd = ENV["BUNDLER_SPEC_ORIGINAL_CMD"]
- if bundler_spec_original_cmd
- require "shellwords"
- cmd = [*Shellwords.shellsplit(bundler_spec_original_cmd), *ARGV]
- else
- cmd = [$PROGRAM_NAME, *ARGV]
- cmd.unshift(Gem.ruby) unless File.executable?($PROGRAM_NAME)
- end
+ cmd = [$PROGRAM_NAME, *ARGV]
+ cmd.unshift(Gem.ruby) unless File.executable?($PROGRAM_NAME)
Bundler.with_original_env do
Kernel.exec(
@@ -98,16 +77,14 @@ module Bundler
def needs_switching?
autoswitching_applies? &&
- Bundler.settings[:version] != "system" &&
- released?(restart_version) &&
- !running?(restart_version) &&
+ released?(lockfile_version) &&
+ !running?(lockfile_version) &&
!updating?
end
def autoswitching_applies?
ENV["BUNDLER_VERSION"].nil? &&
Bundler.rubygems.supports_bundler_trampolining? &&
- ruby_can_restart_with_same_arguments? &&
SharedHelpers.in_bundle? &&
lockfile_version
end
@@ -137,7 +114,7 @@ module Bundler
source = Bundler::Source::Rubygems.new("remotes" => "https://rubygems.org")
source.remote!
source.add_dependency_names("bundler")
- source.specs.select(&:matches_current_metadata?)
+ source.specs
end
end
@@ -167,10 +144,6 @@ module Bundler
!version.to_s.end_with?(".dev")
end
- def ruby_can_restart_with_same_arguments?
- $PROGRAM_NAME != "-e"
- end
-
def updating?
"update".start_with?(ARGV.first || " ") && ARGV[1..-1].any? {|a| a.start_with?("--bundler") }
end
@@ -178,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
@@ -190,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 878747a53b..a76a792743 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -7,6 +7,7 @@ module Bundler
autoload :Validator, File.expand_path("settings/validator", __dir__)
BOOL_KEYS = %w[
+ allow_deployment_source_credential_changes
allow_offline_install
auto_clean_without_path
auto_install
@@ -42,23 +43,10 @@ module Bundler
setup_makes_kernel_gem_public
silence_deprecations
silence_root_warning
+ suppress_install_using_messages
update_requires_all_flag
].freeze
- REMEMBERED_KEYS = %w[
- bin
- cache_all
- clean
- deployment
- frozen
- no_prune
- path
- shebang
- path.system
- without
- with
- ].freeze
-
NUMBER_KEYS = %w[
jobs
redirect
@@ -87,7 +75,6 @@ module Bundler
shebang
system_bindir
trust-policy
- version
].freeze
DEFAULT_CONFIG = {
@@ -97,39 +84,25 @@ 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)
- @local_root = root || Pathname.new(".bundle").expand_path
-
- @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
def set_command_option(key, value)
- if !is_remembered(key) || Bundler.feature_flag.forget_cli_options?
+ if Bundler.feature_flag.forget_cli_options?
temporary(key => value)
value
else
@@ -143,7 +116,7 @@ module Bundler
end
def set_local(key, value)
- local_config_file = @local_root.join("config")
+ local_config_file || raise(GemfileNotFound, "Could not locate Gemfile")
set_key(key, value, @local_config, local_config_file)
end
@@ -166,22 +139,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
@@ -189,7 +157,7 @@ module Bundler
def mirror_for(uri)
if uri.is_a?(String)
require_relative "vendored_uri"
- uri = Gem::URI(uri)
+ uri = Bundler::URI(uri)
end
gem_mirrors.for(uri.to_s).uri
@@ -251,6 +219,7 @@ module Bundler
def path
configs.each do |_level, settings|
path = value_for("path", settings)
+ path = "vendor/bundle" if value_for("deployment", settings) && path.nil?
path_system = value_for("path.system", settings)
disabled_shared_gems = value_for("disable_shared_gems", settings)
next if path.nil? && path_system.nil? && disabled_shared_gems.nil?
@@ -258,9 +227,7 @@ module Bundler
return Path.new(path, system_path)
end
- path = "vendor/bundle" if self[:deployment]
-
- Path.new(path, false)
+ Path.new(nil, false)
end
Path = Struct.new(:explicit_path, :system_path) do
@@ -328,18 +295,18 @@ 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,
- global: @global_config,
- default: DEFAULT_CONFIG,
+ {
+ :temporary => @temporary,
+ :local => @local_config,
+ :env => @env_config,
+ :global => @global_config,
+ :default => DEFAULT_CONFIG,
}
end
@@ -360,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
@@ -381,15 +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))
- end
-
- def is_remembered(key)
- REMEMBERED_KEYS.include?(self.class.key_to_s(key))
+ ARRAY_KEYS.include?(key.to_s)
end
def is_credential(key)
@@ -412,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)
@@ -427,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?
@@ -491,57 +449,41 @@ 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)|
- k = k.dup
- k << "/" if /https?:/i.match?(k) && !k.end_with?("/", "__#{FALLBACK_TIMEOUT_URI_OPTION.upcase}")
- k.gsub!(".", "__")
-
- unless k.start_with?("#")
- 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("-", "___")
- end
-
- 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 (`___`)."
+
+ new_k = k.gsub("-", "___")
end
+ 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
-
- FALLBACK_TIMEOUT_URI_OPTION = "fallback_timeout"
+ PER_URI_OPTIONS = %w[
+ fallback_timeout
+ ].freeze
NORMALIZE_URI_OPTIONS_PATTERN =
/
\A
(\w+\.)? # optional prefix key
(https?.*?) # URI
- (\.#{FALLBACK_TIMEOUT_URI_OPTION})? # optional suffix key
+ (\.#{Regexp.union(PER_URI_OPTIONS)})? # optional suffix key
\z
- /ix
+ /ix.freeze
def self.key_for(key)
- key = key_to_s(key)
- key = normalize_uri(key) if key.start_with?("http", "mirror.http")
- key = key.gsub(".", "__")
- key.gsub!("-", "___")
- key.upcase!
-
- key.gsub(/\A([ #]*)/, '\1BUNDLE_')
+ key = normalize_uri(key).to_s if key.is_a?(String) && key.start_with?("http", "mirror.http")
+ key = key.to_s.gsub(".", "__").gsub("-", "___").upcase
+ "BUNDLE_#{key}"
end
# TODO: duplicates Rubygems#normalize_uri
@@ -553,42 +495,13 @@ module Bundler
uri = $2
suffix = $3
end
- uri = URINormalizer.normalize_suffix(uri)
+ uri = "#{uri}/" unless uri.end_with?("/")
require_relative "vendored_uri"
- uri = Gem::URI(uri)
+ uri = Bundler::URI(uri)
unless uri.absolute?
raise ArgumentError, format("Gem sources must be absolute. You provided '%s'.", uri)
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 Gem::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 Gem::URI::HTTP
- key.to_s
- else
- raise ArgumentError, "Invalid key: #{key.inspect}"
- end
- end
- end
end
end
diff --git a/lib/bundler/setup.rb b/lib/bundler/setup.rb
index 5a0fd8e0e3..32e9b2d7c0 100644
--- a/lib/bundler/setup.rb
+++ b/lib/bundler/setup.rb
@@ -5,12 +5,6 @@ require_relative "shared_helpers"
if Bundler::SharedHelpers.in_bundle?
require_relative "../bundler"
- # autoswitch to locked Bundler version if available
- Bundler.auto_switch
-
- # try to auto_install first before we get to the `Bundler.ui.silence`, so user knows what is happening
- Bundler.auto_install
-
if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"]
begin
Bundler.ui.silence { Bundler.setup }
@@ -18,13 +12,7 @@ if Bundler::SharedHelpers.in_bundle?
Bundler.ui.error e.message
Bundler.ui.warn e.backtrace.join("\n") if ENV["DEBUG"]
if e.is_a?(Bundler::GemNotFound)
- default_bundle = Gem.bin_path("bundler", "bundle")
- current_bundle = Bundler::SharedHelpers.bundle_bin_path
- suggested_bundle = default_bundle == current_bundle ? "bundle" : current_bundle
- suggested_cmd = "#{suggested_bundle} install"
- original_gemfile = Bundler.original_env["BUNDLE_GEMFILE"]
- suggested_cmd += " --gemfile #{original_gemfile}" if original_gemfile
- Bundler.ui.warn "Run `#{suggested_cmd}` to install missing gems."
+ Bundler.ui.warn "Run `bundle install` to install missing gems."
end
exit e.status_code
end
diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb
index e55632b89f..794a03e62d 100644
--- a/lib/bundler/shared_helpers.rb
+++ b/lib/bundler/shared_helpers.rb
@@ -1,27 +1,25 @@
# frozen_string_literal: true
+require "pathname"
+require "rbconfig"
+
require_relative "version"
+require_relative "constants"
require_relative "rubygems_integration"
require_relative "current_ruby"
-autoload :Pathname, "pathname"
-
module Bundler
- autoload :WINDOWS, File.expand_path("constants", __dir__)
- autoload :FREEBSD, File.expand_path("constants", __dir__)
- autoload :NULL, File.expand_path("constants", __dir__)
-
module SharedHelpers
def root
gemfile = find_gemfile
raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
- Pathname.new(gemfile).expand_path.parent
+ Pathname.new(gemfile).tap {|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path.parent
end
def default_gemfile
gemfile = find_gemfile
raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
- Pathname.new(gemfile).expand_path
+ Pathname.new(gemfile).tap {|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path
end
def default_lockfile
@@ -30,7 +28,7 @@ module Bundler
case gemfile.basename.to_s
when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked"))
else Pathname.new("#{gemfile}.lock")
- end
+ end.tap {|x| x.untaint if RUBY_VERSION < "2.7" }
end
def default_bundle_dir
@@ -102,7 +100,7 @@ module Bundler
#
# @see {Bundler::PermissionError}
def filesystem_access(path, action = :write, &block)
- yield(path.dup)
+ yield(path.dup.tap {|x| x.untaint if RUBY_VERSION < "2.7" })
rescue Errno::EACCES
raise PermissionError.new(path, action)
rescue Errno::EAGAIN
@@ -119,18 +117,16 @@ module Bundler
raise GenericSystemCallError.new(e, "There was an error accessing `#{path}`.")
end
- def major_deprecation(major_version, message, removed_message: nil, print_caller_location: false)
+ def major_deprecation(major_version, message, print_caller_location: false)
if print_caller_location
caller_location = caller_locations(2, 2).first
- suffix = " (called at #{caller_location.path}:#{caller_location.lineno})"
- message += suffix
- removed_message += suffix if removed_message
+ message = "#{message} (called at #{caller_location.path}:#{caller_location.lineno})"
end
bundler_major_version = Bundler.bundler_major_version
if bundler_major_version > major_version
require_relative "errors"
- raise DeprecatedError, "[REMOVED] #{removed_message || message}"
+ raise DeprecatedError, "[REMOVED] #{message}"
end
return unless bundler_major_version >= major_version && prints_major_deprecations?
@@ -164,7 +160,7 @@ module Bundler
" (was expecting #{old_deps.map(&:to_s)}, but the real spec has #{new_deps.map(&:to_s)})"
raise APIResponseMismatchError,
"Downloading #{spec.full_name} revealed dependencies not in the API or the lockfile (#{extra_deps.join(", ")})." \
- "\nRunning `bundle update #{spec.name}` should fix the problem."
+ "\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem."
end
def pretty_dependency(dep)
@@ -197,40 +193,10 @@ module Bundler
Digest(name)
end
- def checksum_for_file(path, digest)
- return unless path.file?
- # This must use File.read instead of Digest.file().hexdigest
- # 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(digest).new
- buf = String.new(capacity: 16_384, encoding: Encoding::BINARY)
- digest << buf while f.read(16_384, buf)
- digest.hexdigest
- end
- end
- end
-
def write_to_gemfile(gemfile_path, contents)
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
@@ -269,7 +235,7 @@ module Bundler
def search_up(*names)
previous = nil
- current = File.expand_path(SharedHelpers.pwd)
+ current = File.expand_path(SharedHelpers.pwd).tap {|x| x.untaint if RUBY_VERSION < "2.7" }
until !File.directory?(current) || current == previous
if ENV["BUNDLER_SPEC_RUN"]
@@ -306,13 +272,6 @@ module Bundler
public :set_env
def set_bundle_variables
- Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", bundle_bin_path
- Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s
- Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION
- Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__)
- end
-
- def bundle_bin_path
# bundler exe & lib folders have same root folder, typical gem installation
exe_file = File.expand_path("../../exe/bundle", __dir__)
@@ -322,9 +281,11 @@ module Bundler
# bundler is a default gem, exe path is separate
exe_file = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file)
- exe_file
+ Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file
+ Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s
+ Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION
+ Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__) unless RUBY_VERSION < "2.7"
end
- public :bundle_bin_path
def set_path
validate_bundle_path
@@ -336,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.include?(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..69804a2e63 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
@@ -102,7 +100,7 @@ module Bundler
end
def print_using_message(message)
- if !message.include?("(was ")
+ if !message.include?("(was ") && Bundler.feature_flag.suppress_install_using_messages?
Bundler.ui.debug message
else
Bundler.ui.info message
diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb
index ef36efb3f4..b8ee4029b4 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
@@ -20,7 +19,7 @@ module Bundler
# Stringify options that could be set as symbols
%w[ref branch tag revision].each {|k| options[k] = options[k].to_s if options[k] }
- @uri = URINormalizer.normalize_suffix(options["uri"] || "", trailing_slash: false)
+ @uri = options["uri"] || ""
@safe_uri = URICredentialsFilter.credential_filtered_uri(@uri)
@branch = options["branch"]
@ref = options["ref"] || options["branch"] || options["tag"]
@@ -32,20 +31,6 @@ module Bundler
@local = false
end
- def remote!
- return if @allow_remote
-
- @local_specs = nil
- @allow_remote = true
- end
-
- def cached!
- return if @allow_cached
-
- @local_specs = nil
- @allow_cached = true
- end
-
def self.from_lock(options)
new(options.merge("uri" => options.delete("remote")))
end
@@ -61,53 +46,41 @@ module Bundler
out << " specs:\n"
end
- def to_gemfile
- specifiers = %w[ref branch tag submodules glob].map do |opt|
- "#{opt}: #{options[opt]}" if options[opt]
- end
-
- uri_with_specifiers(specifiers)
- end
-
def hash
- [self.class, uri, ref, branch, name, glob, submodules].hash
+ [self.class, uri, ref, branch, name, version, glob, submodules].hash
end
def eql?(other)
other.is_a?(Git) && uri == other.uri && ref == other.ref &&
branch == other.branch && name == other.name &&
- glob == other.glob &&
+ version == other.version && glob == other.glob &&
submodules == other.submodules
end
alias_method :==, :eql?
- def include?(other)
- other.is_a?(Git) && uri == other.uri &&
- name == other.name &&
- glob == other.glob &&
- submodules == other.submodules
- end
-
def to_s
begin
- at = humanized_ref || current_branch
+ at = if local?
+ path
+ elsif user_ref = options["ref"]
+ if /\A[a-z0-9]{4,}\z/i.match?(ref)
+ shortref_for_display(user_ref)
+ else
+ user_ref
+ end
+ elsif ref
+ ref
+ else
+ current_branch
+ end
rev = "at #{at}@#{shortref_for_display(revision)}"
rescue GitError
""
end
- uri_with_specifiers([rev, glob_for_display])
- end
-
- def identifier
- uri_with_specifiers([humanized_ref, cached_revision, glob_for_display])
- end
-
- def uri_with_specifiers(specifiers)
- specifiers.compact!
-
+ specifiers = [rev, glob_for_display].compact
suffix =
if specifiers.any?
" (#{specifiers.join(", ")})"
@@ -164,8 +137,7 @@ module Bundler
"does not exist. Run `bundle config unset local.#{override_for(original_path)}` to remove the local override"
end
- @local = true
- set_paths!(path)
+ set_local!(path)
# Create a new git proxy without the cached revision
# so the Gemfile.lock always picks up the new revision.
@@ -188,29 +160,31 @@ module Bundler
end
def specs(*)
- set_up_app_cache!(app_cache_path) if use_app_cache?
+ set_local!(app_cache_path) if has_app_cache? && !local?
if requires_checkout? && !@copied
- FileUtils.rm_rf(app_cache_path) if use_app_cache? && git_proxy.not_a_repository?
-
fetch
- checkout
+ git_proxy.copy_to(install_path, submodules)
+ serialize_gemspecs_in(install_path)
+ @copied = true
end
local_specs
end
def install(spec, options = {})
- return if Bundler.settings[:no_install]
force = options[:force]
print_using_message "Using #{version_message(spec, options[:previous_spec])} from #{self}"
if (requires_checkout? && !@copied) || force
- checkout
+ Bundler.ui.debug " * Checking out revision: #{ref}"
+ git_proxy.copy_to(install_path, submodules)
+ serialize_gemspecs_in(install_path)
+ @copied = true
end
- generate_bin_options = { disable_extensions: !spec.missing_extensions?, build_args: options[:build_args] }
+ generate_bin_options = { :disable_extensions => !Bundler.rubygems.spec_missing_extensions?(spec), :build_args => options[:build_args] }
generate_bin(spec, generate_bin_options)
requires_checkout? ? spec.post_install_message : nil
@@ -219,14 +193,12 @@ module Bundler
def cache(spec, custom_path = nil)
app_cache_path = app_cache_path(custom_path)
return unless Bundler.feature_flag.cache_all?
- return if install_path == app_cache_path
- return if cache_path == app_cache_path
+ return if path == app_cache_path
cached!
FileUtils.rm_rf(app_cache_path)
git_proxy.checkout if requires_checkout?
- FileUtils.cp_r("#{cache_path}/.", app_cache_path)
- FileUtils.touch(app_cache_path.join(".bundlecache"))
- FileUtils.rm_rf(Dir.glob(app_cache_path.join("hooks/*.sample")))
+ git_proxy.copy_to(app_cache_path, @submodules)
+ serialize_gemspecs_in(app_cache_path)
end
def load_spec_files
@@ -270,27 +242,6 @@ module Bundler
private
- def checkout
- Bundler.ui.debug " * Checking out revision: #{ref}"
- git_proxy.copy_to(install_path, submodules)
- serialize_gemspecs_in(install_path)
- @copied = true
- end
-
- def humanized_ref
- if local?
- path
- elsif user_ref = options["ref"]
- if /\A[a-z0-9]{4,}\z/i.match?(ref)
- shortref_for_display(user_ref)
- else
- user_ref
- end
- elsif ref
- ref
- end
- end
-
def serialize_gemspecs_in(destination)
destination = destination.expand_path(Bundler.root) if destination.relative?
Dir["#{destination}/#{@glob}"].each do |spec_path|
@@ -299,40 +250,22 @@ module Bundler
# The gemspecs we cache should already be evaluated.
spec = Bundler.load_gemspec(spec_path)
next unless spec
- spec.installed_by_version = Gem::VERSION
+ Bundler.rubygems.set_installed_by_version(spec)
Bundler.rubygems.validate(spec)
File.open(spec_path, "wb") {|file| file.write(spec.to_ruby) }
end
end
- def set_paths!(path)
- set_cache_path!(path)
- set_install_path!(path)
- end
-
- def set_cache_path!(path)
- @git_proxy = nil
- @cache_path = path
- end
-
- def set_install_path!(path)
- @local_specs = nil
- @install_path = path
- end
-
- def set_up_app_cache!(path)
- FileUtils.mkdir_p(path.join("refs"))
- set_cache_path!(path)
+ def set_local!(path)
+ @local = true
+ @local_specs = @git_proxy = nil
+ @cache_path = @install_path = path
end
def has_app_cache?
cached_revision && super
end
- def use_app_cache?
- has_app_cache? && !local?
- end
-
def requires_checkout?
allow_git_ops? && !local? && !cached_revision_checked_out?
end
@@ -365,7 +298,7 @@ module Bundler
if %r{^\w+://(\w+@)?}.match?(uri)
# Downcase the domain component of the URI
# and strip off a trailing slash, if one is present
- input = Gem::URI.parse(uri).normalize.to_s.sub(%r{/$}, "")
+ input = Bundler::URI.parse(uri).normalize.to_s.sub(%r{/$}, "")
else
# If there is no URI scheme, assume it is an ssh/git URI
input = uri
@@ -398,12 +331,9 @@ module Bundler
def validate_spec(_spec); end
def load_gemspec(file)
- dirname = Pathname.new(file).dirname
- SharedHelpers.chdir(dirname.to_s) do
- stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent)
- stub.full_gem_path = dirname.expand_path(root).to_s
- StubSpecification.from_stub(stub)
- end
+ stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent)
+ stub.full_gem_path = Pathname.new(file).dirname.expand_path(root).to_s.tap {|x| x.untaint if RUBY_VERSION < "2.7" }
+ StubSpecification.from_stub(stub)
end
def git_scope
diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb
index 86c45780ae..2a7c8473f5 100644
--- a/lib/bundler/source/git/git_proxy.rb
+++ b/lib/bundler/source/git/git_proxy.rb
@@ -28,9 +28,8 @@ module Bundler
def initialize(command, path, extra_info = nil)
@command = command
- msg = String.new("Git error: command `#{command}`")
- msg << " in directory #{path}" if path
- msg << " has failed."
+ msg = String.new
+ msg << "Git error: command `#{command}` in directory #{path} has failed."
msg << "\n#{extra_info}" if extra_info
super msg
end
@@ -43,13 +42,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 +52,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
@@ -79,21 +66,15 @@ module Bundler
end
def current_branch
- @current_branch ||= with_path do
- git_local("rev-parse", "--abbrev-ref", "HEAD", dir: path).strip
+ @current_branch ||= allowed_with_path do
+ git("rev-parse", "--abbrev-ref", "HEAD", :dir => path).strip
end
end
- def not_a_repository?
- _, status = git_null("rev-parse", "--resolve-git-dir", path.to_s, dir: path)
-
- !status.success?
- end
-
def contains?(commit)
allowed_with_path do
- result, status = git_null("branch", "--contains", commit, dir: path)
- status.success? && result.match?(/^\* (.*)$/)
+ result, status = git_null("branch", "--contains", commit, :dir => path)
+ status.success? && result =~ /^\* (.*)$/
end
end
@@ -102,7 +83,7 @@ module Bundler
end
def full_version
- @full_version ||= git_local("--version").sub(/git version\s*/, "").strip
+ @full_version ||= git("--version").sub(/git version\s*/, "").strip
end
def checkout
@@ -136,20 +117,15 @@ 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, :dir => destination if @commit_ref
- git "fetch", "--force", "--quiet", *extra_fetch_args(ref), dir: destination
- end
-
- git "reset", "--hard", @revision, dir: destination
+ git "reset", "--hard", @revision, :dir => destination
if submodules
- git_retry "submodule", "update", "--init", "--recursive", dir: destination
+ git_retry "submodule", "update", "--init", "--recursive", :dir => destination
elsif Gem::Version.create(version) >= Gem::Version.create("2.9.0")
inner_command = "git -C $toplevel submodule deinit --force $sm_path"
- git_retry "submodule", "foreach", "--quiet", inner_command, dir: destination
+ git_retry "submodule", "foreach", "--quiet", inner_command, :dir => destination
end
end
@@ -163,8 +139,8 @@ module Bundler
out, err, status = capture(command, path)
return out if status.success?
- if err.include?("couldn't find remote ref") || err.include?("not our ref")
- raise MissingGitRevisionError.new(command_with_no_credentials, path, commit || explicit_ref, credential_filtered_uri)
+ if err.include?("couldn't find remote ref")
+ raise MissingGitRevisionError.new(command_with_no_credentials, path, explicit_ref, credential_filtered_uri)
else
raise GitCommandError.new(command_with_no_credentials, path, err)
end
@@ -177,29 +153,9 @@ module Bundler
SharedHelpers.filesystem_access(path.dirname) do |p|
FileUtils.mkdir_p(p)
end
+ git_retry "clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s
- command = ["clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s]
- command_with_no_credentials = check_allowed(command)
-
- Bundler::Retry.new("`#{command_with_no_credentials}`", [MissingGitRevisionError]).attempts do
- _, err, status = capture(command, nil)
- return extra_ref if status.success?
-
- 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
- idx = command.index("--depth")
- if idx
- command.delete_at(idx)
- command.delete_at(idx)
- command_with_no_credentials = check_allowed(command)
-
- err += "Retrying without --depth argument."
- end
- raise GitCommandError.new(command_with_no_credentials, path, err)
- end
- end
+ extra_ref
end
def clone_needs_unshallow?
@@ -230,6 +186,8 @@ module Bundler
end
def refspec
+ commit = pinned_to_full_sha? ? ref : @revision
+
if commit
@commit_ref = "refs/#{commit}-sha"
return "#{commit}:#{@commit_ref}"
@@ -248,10 +206,6 @@ module Bundler
"#{reference}:#{reference}"
end
- def commit
- @commit ||= pinned_to_full_sha? ? ref : @revision
- end
-
def fully_qualified_ref
if branch
"refs/heads/#{branch}"
@@ -263,50 +217,42 @@ module Bundler
end
def not_pinned?
- branch_option || ref.nil?
+ branch || tag || 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)
check_allowed(command)
- capture(command, dir, ignore_err: true)
+ capture(command, dir, :ignore_err => true)
end
def git_retry(*command, dir: nil)
command_with_no_credentials = check_allowed(command)
Bundler::Retry.new("`#{command_with_no_credentials}` at #{dir || SharedHelpers.pwd}").attempts do
- git(*command, dir: dir)
+ git(*command, :dir => dir)
end
end
def git(*command, dir: nil)
- run_command(*command, dir: dir) do |unredacted_command|
- check_allowed(unredacted_command)
- end
- end
+ command_with_no_credentials = check_allowed(command)
- def git_local(*command, dir: nil)
- run_command(*command, dir: dir) do |unredacted_command|
- redact_and_check_presence(unredacted_command)
- end
+ out, err, status = capture(command, dir)
+
+ raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, err) unless status.success?
+
+ Bundler.ui.warn err unless err.empty?
+
+ out
end
def has_revision_cached?
return unless @revision && path.exist?
- git("cat-file", "-e", @revision, dir: path)
+ git("cat-file", "-e", @revision, :dir => path)
true
rescue GitError
false
@@ -329,16 +275,18 @@ module Bundler
end
def verify(reference)
- git("rev-parse", "--verify", reference, dir: path).strip
+ git("rev-parse", "--verify", reference, :dir => path).strip
end
# Adds credentials to the URI
def configured_uri
if /https?:/.match?(uri)
- remote = Gem::URI(uri)
+ remote = Bundler::URI(uri)
config_auth = Bundler.settings[remote.to_s] || Bundler.settings[remote.host]
remote.userinfo ||= config_auth
remote.to_s
+ elsif File.exist?(uri)
+ "file://#{uri}"
else
uri.to_s
end
@@ -368,30 +316,12 @@ module Bundler
end
def check_allowed(command)
- command_with_no_credentials = redact_and_check_presence(command)
+ require "shellwords"
+ command_with_no_credentials = URICredentialsFilter.credential_filtered_string("git #{command.shelljoin}", uri)
raise GitNotAllowedError.new(command_with_no_credentials) unless allow?
command_with_no_credentials
end
- def redact_and_check_presence(command)
- raise GitNotInstalledError.new unless Bundler.git_present?
-
- require "shellwords"
- URICredentialsFilter.credential_filtered_string("git #{command.shelljoin}", uri)
- end
-
- def run_command(*command, dir: nil)
- command_with_no_credentials = yield(command)
-
- out, err, status = capture(command, dir)
-
- raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, err) unless status.success?
-
- Bundler.ui.warn err unless err.empty?
-
- out
- end
-
def capture(cmd, dir, ignore_err: false)
SharedHelpers.with_clean_git_env do
require "open3"
@@ -411,7 +341,7 @@ module Bundler
if Bundler.feature_flag.bundler_3_mode? || supports_minus_c?
["git", "-C", dir.to_s, *cmd]
else
- ["git", *cmd, { chdir: dir.to_s }]
+ ["git", *cmd, { :chdir => dir.to_s }]
end
end
@@ -422,12 +352,7 @@ module Bundler
args += ["--single-branch"]
args.unshift("--no-tags") if supports_cloning_with_no_tags?
- # If there's a locked revision, no need to clone any specific branch
- # or tag, since we will end up checking out that locked revision
- # anyways.
- return args if @revision
-
- args += ["--branch", branch_option] if branch_option
+ args += ["--branch", branch || tag] if branch || tag
args
end
@@ -437,16 +362,12 @@ 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
@@ -455,10 +376,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 6b05e17727..593da6d1a7 100644
--- a/lib/bundler/source/metadata.rb
+++ b/lib/bundler/source/metadata.rb
@@ -5,29 +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"]
- raise CorruptBundlerInstallError.new(local_spec) if local_spec.version.to_s != Bundler::VERSION
+ 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 d4c530e922..20975e20ca 100644
--- a/lib/bundler/source/path.rb
+++ b/lib/bundler/source/path.rb
@@ -11,13 +11,15 @@ module Bundler
protected :original_path
- DEFAULT_GLOB = "{,*,*/*}.gemspec"
+ DEFAULT_GLOB = "{,*,*/*}.gemspec".freeze
def initialize(options)
- @checksum_store = Checksum::Store.new
@options = options.dup
@glob = options["glob"] || DEFAULT_GLOB
+ @allow_cached = false
+ @allow_remote = false
+
@root_path = options["root_path"] || root
if options["path"]
@@ -38,6 +40,16 @@ module Bundler
@original_path = @path
end
+ def remote!
+ @local_specs = nil
+ @allow_remote = true
+ end
+
+ def cached!
+ @local_specs = nil
+ @allow_cached = true
+ end
+
def self.from_lock(options)
new(options.merge("path" => options.delete("remote")))
end
@@ -53,8 +65,6 @@ module Bundler
"source at `#{@path}`"
end
- alias_method :to_gemfile, :path
-
def hash
[self.class, expanded_path, version].hash
end
@@ -75,7 +85,7 @@ module Bundler
using_message = "Using #{version_message(spec, options[:previous_spec])} from #{self}"
using_message += " and installing its executables" unless spec.executables.empty?
print_using_message using_message
- generate_bin(spec, disable_extensions: true)
+ generate_bin(spec, :disable_extensions => true)
nil # no post-install message
end
@@ -150,7 +160,7 @@ module Bundler
def load_gemspec(file)
return unless spec = Bundler.load_gemspec(file)
- spec.installed_by_version = Gem::VERSION
+ Bundler.rubygems.set_installed_by_version(spec)
spec
end
@@ -215,7 +225,7 @@ module Bundler
# Some gem authors put absolute paths in their gemspec
# and we have to save them from themselves
spec.files = spec.files.map do |path|
- next path unless /\A#{Pathname::SEPARATOR_PAT}/o.match?(path)
+ next path unless /\A#{Pathname::SEPARATOR_PAT}/.match?(path)
next if File.directory?(path)
begin
Pathname.new(path).relative_path_from(gem_dir).to_s
@@ -226,10 +236,10 @@ module Bundler
installer = Path::Installer.new(
spec,
- env_shebang: false,
- disable_extensions: options[:disable_extensions],
- build_args: options[:build_args],
- bundler_extension_cache_path: extension_cache_path(spec)
+ :env_shebang => false,
+ :disable_extensions => options[:disable_extensions],
+ :build_args => options[:build_args],
+ :bundler_extension_cache_path => extension_cache_path(spec)
)
installer.post_install
rescue Gem::InvalidSpecificationException => e
diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb
index 36185561fa..c39071705a 100644
--- a/lib/bundler/source/rubygems.rb
+++ b/lib/bundler/source/rubygems.rb
@@ -7,10 +7,12 @@ module Bundler
class Rubygems < Source
autoload :Remote, File.expand_path("rubygems/remote", __dir__)
+ # Use the API when installing less than X gems
+ API_REQUEST_LIMIT = 500
# Ask for X gems per API request
API_REQUEST_SIZE = 50
- attr_accessor :remotes
+ attr_reader :remotes, :caches
def initialize(options = {})
@options = options
@@ -19,15 +21,9 @@ module Bundler
@allow_remote = false
@allow_cached = false
@allow_local = options["allow_local"] || false
- @checksum_store = Checksum::Store.new
+ @caches = [cache_path, *Bundler.rubygems.gem_cache]
Array(options["remotes"]).reverse_each {|r| add_remote(r) }
-
- @lockfile_remotes = @remotes if options["from_lockfile"]
- end
-
- def caches
- @caches ||= [cache_path, *Bundler.rubygems.gem_cache]
end
def local_only!
@@ -52,11 +48,10 @@ module Bundler
end
def cached!
- return unless File.exist?(cache_path)
-
return if @allow_cached
@specs = nil
+ @allow_local = true
@allow_cached = true
end
@@ -92,14 +87,13 @@ module Bundler
end
def self.from_lock(options)
- options["remotes"] = Array(options.delete("remote")).reverse
- new(options.merge("from_lockfile" => true))
+ new(options)
end
def to_lock
out = String.new("GEM\n")
- lockfile_remotes.reverse_each do |remote|
- out << " remote: #{remote}\n"
+ remotes.reverse_each do |remote|
+ out << " remote: #{suppress_configured_credentials remote}\n"
end
out << " specs:\n"
end
@@ -128,27 +122,29 @@ module Bundler
end
end
alias_method :name, :identifier
- alias_method :to_gemfile, :identifier
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
- index.merge!(installed_specs) if @allow_local
-
- # complete with default specs, only if not already available in the
- # index through remote, cached, or installed specs
- index.use(default_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
def install(spec, options = {})
- if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
+ force = options[:force]
+ ensure_builtin_gems_cached = options[:ensure_builtin_gems_cached]
+
+ if ensure_builtin_gems_cached && spec.default_gem? && !cached_path(spec)
+ cached_built_in_gem(spec) unless spec.remote
+ force = true
+ end
+
+ if installed?(spec) && !force
print_using_message "Using #{version_message(spec, options[:previous_spec])}"
return nil # no post-install message
end
@@ -171,14 +167,15 @@ module Bundler
installer = Bundler::RubyGemsGemInstaller.at(
path,
- security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
- install_dir: install_path.to_s,
- bin_dir: bin_path.to_s,
- ignore_dependencies: true,
- wrappers: true,
- env_shebang: true,
- build_args: options[:build_args],
- bundler_extension_cache_path: extension_cache_path(spec)
+ :security_policy => Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
+ :install_dir => install_path.to_s,
+ :bin_dir => bin_path.to_s,
+ :ignore_dependencies => true,
+ :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)
)
if spec.remote
@@ -196,8 +193,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
@@ -206,7 +201,6 @@ module Bundler
spec.full_gem_path = installed_spec.full_gem_path
spec.loaded_from = installed_spec.loaded_from
- spec.base_dir = installed_spec.base_dir
spec.post_install_message
end
@@ -222,13 +216,12 @@ module Bundler
raise InstallError, e.message
end
- def cached_built_in_gem(spec, local: false)
- cached_path = cached_gem(spec)
- if cached_path.nil? && !local
+ def cached_built_in_gem(spec)
+ cached_path = cached_path(spec)
+ if cached_path.nil?
remote_spec = remote_specs.search(spec).first
if remote_spec
cached_path = fetch_gem(remote_spec)
- spec.remote = remote_spec.remote
else
Bundler.ui.warn "#{spec.full_name} is built in to Ruby, and can't be cached because your Gemfile doesn't have any sources that contain it."
end
@@ -242,7 +235,7 @@ module Bundler
end
def spec_names
- if dependency_api_available?
+ if @allow_remote && dependency_api_available?
remote_specs.spec_names
else
[]
@@ -250,25 +243,22 @@ module Bundler
end
def unmet_deps
- if dependency_api_available?
+ if @allow_remote && dependency_api_available?
remote_specs.unmet_dependency_names
else
[]
end
end
- def remote_fetchers
- @remote_fetchers ||= remotes.to_h do |uri|
- remote = Source::Rubygems::Remote.new(uri)
- [remote, Bundler::Fetcher.new(remote)]
- end.freeze
- end
-
def fetchers
- @fetchers ||= remote_fetchers.values.freeze
+ @fetchers ||= remotes.map do |uri|
+ remote = Source::Rubygems::Remote.new(uri)
+ Bundler::Fetcher.new(remote)
+ end
end
def double_check_for(unmet_dependency_names)
+ return unless @allow_remote
return unless dependency_api_available?
unmet_dependency_names = unmet_dependency_names.call
@@ -283,9 +273,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
@@ -314,7 +302,11 @@ module Bundler
end
def credless_remotes
- remotes.map(&method(:remove_auth))
+ if Bundler.settings[:allow_deployment_source_credential_changes]
+ remotes.map(&method(:remove_auth))
+ else
+ remotes.map(&method(:suppress_configured_credentials))
+ end
end
def remotes_for_spec(spec)
@@ -325,10 +317,18 @@ module Bundler
end
def cached_gem(spec)
+ if spec.default_gem?
+ cached_built_in_gem(spec)
+ else
+ cached_path(spec)
+ end
+ end
+
+ def cached_path(spec)
global_cache_path = download_cache_path(spec)
- caches << global_cache_path if global_cache_path
+ @caches << global_cache_path if global_cache_path
- possibilities = caches.map {|p| package_path(p, spec) }
+ possibilities = @caches.map {|p| package_path(p, spec) }
possibilities.find {|p| File.exist?(p) }
end
@@ -337,14 +337,24 @@ module Bundler
end
def normalize_uri(uri)
- uri = URINormalizer.normalize_suffix(uri.to_s)
+ uri = uri.to_s
+ uri = "#{uri}/" unless %r{/$}.match?(uri)
require_relative "../vendored_uri"
- uri = Gem::URI(uri)
+ uri = Bundler::URI(uri)
raise ArgumentError, "The source must be an absolute URI. For example:\n" \
- "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(Gem::URI::HTTP) && uri.host.nil?)
+ "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(Bundler::URI::HTTP) && uri.host.nil?)
uri
end
+ def suppress_configured_credentials(remote)
+ remote_nouser = remove_auth(remote)
+ if remote.userinfo && remote.userinfo == Bundler.settings[remote_nouser]
+ remote_nouser
+ else
+ remote
+ end
+ end
+
def remove_auth(remote)
if remote.user || remote.password
remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s
@@ -355,18 +365,12 @@ module Bundler
def installed_specs
@installed_specs ||= Index.build do |idx|
- Bundler.rubygems.installed_specs.reverse_each do |spec|
- spec.source = self
- next if spec.ignored?
- idx << spec
- end
- end
- end
-
- def default_specs
- @default_specs ||= Index.build do |idx|
- Bundler.rubygems.default_specs.each do |spec|
+ Bundler.rubygems.all_specs.reverse_each do |spec|
spec.source = self
+ if Bundler.rubygems.spec_missing_extensions?(spec, false)
+ Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions"
+ next
+ end
idx << spec
end
end
@@ -374,9 +378,10 @@ 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|
+ next if /^bundler\-[\d\.]+?\.gem/.match?(gemfile)
s ||= Bundler.rubygems.spec_from_gem(gemfile)
s.source = self
idx << s
@@ -387,30 +392,36 @@ 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)
+
+ # because ensuring we have all the gems we need involves downloading
+ # the gemspecs of those gems, if the non-api sites contain more than
+ # about 500 gems, we treat all sites as non-api for speed.
+ allow_api = idx.size < API_REQUEST_LIMIT && dependency_names.size < API_REQUEST_LIMIT
+ Bundler.ui.debug "Need to query more than #{API_REQUEST_LIMIT} gems." \
+ " Downloading full index instead..." unless allow_api
+
+ 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
@@ -456,10 +467,6 @@ module Bundler
private
- def lockfile_remotes
- @lockfile_remotes || credless_remotes
- end
-
# Checks if the requested spec exists in the global cache. If it does,
# we copy it to the download path, and if it does not, we download it.
#
@@ -475,8 +482,7 @@ module Bundler
def download_gem(spec, download_cache_path, previous_spec = nil)
uri = spec.remote.uri
Bundler.ui.confirm("Fetching #{version_message(spec, previous_spec)}")
- gem_remote_fetcher = remote_fetchers.fetch(spec.remote).gem_remote_fetcher
- Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher)
+ Bundler.rubygems.download_gem(spec, uri, download_cache_path)
end
# Returns the global cache path of the calling Rubygems::Source object.
diff --git a/lib/bundler/source/rubygems/remote.rb b/lib/bundler/source/rubygems/remote.rb
index 9c5c06de24..82c850ffbb 100644
--- a/lib/bundler/source/rubygems/remote.rb
+++ b/lib/bundler/source/rubygems/remote.rb
@@ -48,7 +48,7 @@ module Bundler
end
uri
- rescue Gem::URI::InvalidComponentError
+ rescue Bundler::URI::InvalidComponentError
error_message = "Please CGI escape your usernames and passwords before " \
"setting them for authentication."
raise HTTPError.new(error_message)
diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb
index 5f9dd68f17..63798db941 100644
--- a/lib/bundler/source_list.rb
+++ b/lib/bundler/source_list.rb
@@ -22,7 +22,6 @@ module Bundler
@metadata_source = Source::Metadata.new
@merged_gem_lockfile_sections = false
- @local_mode = true
end
def merged_gem_lockfile_sections?
@@ -74,10 +73,6 @@ module Bundler
global_rubygems_source
end
- def local_mode?
- @local_mode
- end
-
def default_source
global_path_source || global_rubygems_source
end
@@ -106,6 +101,10 @@ module Bundler
source_list_for(source).find {|s| equivalent_source?(source, s) }
end
+ def get_with_fallback(source)
+ get(source) || default_source
+ end
+
def lock_sources
lock_other_sources + lock_rubygems_sources
end
@@ -145,17 +144,11 @@ module Bundler
all_sources.each(&:local_only!)
end
- def local!
- all_sources.each(&:local!)
- end
-
def cached!
all_sources.each(&:cached!)
end
def remote!
- @local_mode = false
-
all_sources.each(&:remote!)
end
@@ -168,11 +161,7 @@ module Bundler
end
def map_sources(replacement_sources)
- rubygems = @rubygems_sources.map do |source|
- replace_rubygems_source(replacement_sources, source) || source
- end
-
- git, plugin = [@git_sources, @plugin_sources].map do |sources|
+ rubygems, git, plugin = [@rubygems_sources, @git_sources, @plugin_sources].map do |sources|
sources.map do |source|
replacement_sources.find {|s| s == source } || source
end
@@ -186,22 +175,13 @@ module Bundler
end
def global_replacement_source(replacement_sources)
- replacement_source = replace_rubygems_source(replacement_sources, global_rubygems_source)
+ replacement_source = replacement_sources.find {|s| s == global_rubygems_source }
return global_rubygems_source unless replacement_source
replacement_source.local!
replacement_source
end
- def replace_rubygems_source(replacement_sources, gemfile_source)
- replacement_source = replacement_sources.find {|s| s == gemfile_source }
- return unless replacement_source
-
- # locked sources never include credentials so always prefer remotes from the gemfile
- replacement_source.remotes = gemfile_source.remotes
- replacement_source
- end
-
def different_sources?(lock_sources, replacement_sources)
!equivalent_sources?(lock_sources, replacement_sources)
end
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index 96c36c2dec..7478bd9ca2 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -24,7 +24,6 @@ module Bundler
name = dep[0].name
platform = dep[1]
- incomplete = false
key = [name, platform]
next if handled.key?(key)
@@ -37,66 +36,31 @@ module Bundler
specs_for_dep.first.dependencies.each do |d|
next if d.type == :development
- incomplete = true if d.name != "bundler" && lookup[d.name].nil?
deps << [d, dep[1]]
end
- else
- incomplete = true
+ elsif check
+ @incomplete_specs += lookup[name]
end
-
- if incomplete && check
- @incomplete_specs += lookup[name] || [LazySpecification.new(name, nil, nil)]
- end
- end
-
- specs.uniq
- end
-
- def add_extra_platforms!(platforms)
- return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty?
-
- new_platforms = all_platforms.select do |platform|
- next if platforms.include?(platform)
- next unless GemHelpers.generic(platform) == Gem::Platform::RUBY
-
- complete_platform(platform)
- end
- return platforms if new_platforms.empty?
-
- platforms.concat(new_platforms)
-
- less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && Bundler.local_platform === platform && platform === Bundler.local_platform }
- platforms.delete(Bundler.local_platform) if less_specific_platform
-
- platforms
- end
-
- def validate_deps(s)
- s.runtime_dependencies.each do |dep|
- next if dep.name == "bundler"
-
- return :missing unless names.include?(dep.name)
- return :invalid if none? {|spec| dep.matches_spec?(spec) }
end
- :valid
+ specs
end
def [](key)
key = key.name if key.respond_to?(:name)
- lookup[key]&.reverse || []
+ lookup[key].reverse
end
def []=(key, value)
@specs << value
-
- reset!
+ @lookup = nil
+ @sorted = nil
end
- def delete(specs)
- Array(specs).each {|spec| @specs.delete(spec) }
-
- reset!
+ def delete(spec)
+ @specs.delete(spec)
+ @lookup = nil
+ @sorted = nil
end
def sort!
@@ -130,12 +94,8 @@ module Bundler
end
end
- def incomplete_for_platform?(deps, platform)
- return false if @specs.empty?
-
- @incomplete_specs = []
-
- self.for(deps, true, [platform])
+ def incomplete_ruby_specs?(deps)
+ self.for(deps, true, [Gem::Platform::RUBY])
@incomplete_specs.any?
end
@@ -144,6 +104,16 @@ module Bundler
@specs.select {|s| s.is_a?(LazySpecification) }
end
+ def merge(set)
+ arr = sorted.dup
+ set.each do |set_spec|
+ full_name = set_spec.full_name
+ next if arr.any? {|spec| spec.full_name == full_name }
+ arr << set_spec
+ end
+ SpecSet.new(arr)
+ end
+
def -(other)
SpecSet.new(to_a - other.to_a)
end
@@ -152,20 +122,14 @@ module Bundler
@specs.detect {|spec| spec.name == name && spec.match_platform(platform) }
end
- def specs_compatible_with(other)
- select do |spec|
- other.valid?(spec)
- end
- end
-
def delete_by_name(name)
@specs.reject! {|spec| spec.name == name }
-
- reset!
+ @lookup = nil
+ @sorted = nil
end
def what_required(spec)
- unless req = find {|s| s.runtime_dependencies.any? {|d| d.name == spec.name } }
+ unless req = find {|s| s.dependencies.any? {|d| d.type == :runtime && d.name == spec.name } }
return [spec]
end
what_required(req) << spec
@@ -191,56 +155,8 @@ module Bundler
sorted.each(&b)
end
- def names
- lookup.keys
- end
-
- def valid?(s)
- s.matches_current_metadata? && valid_dependencies?(s)
- end
-
private
- def reset!
- @sorted = nil
- @lookup = nil
- end
-
- def complete_platform(platform)
- new_specs = []
-
- valid_platform = lookup.all? do |_, specs|
- spec = specs.first
- matching_specs = spec.source.specs.search([spec.name, spec.version])
- platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).find do |s|
- valid?(s)
- end
-
- if platform_spec
- new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec)
- true
- else
- false
- end
- end
-
- if valid_platform && new_specs.any?
- @specs.concat(new_specs)
-
- reset!
- end
-
- valid_platform
- end
-
- def all_platforms
- @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq
- end
-
- def valid_dependencies?(s)
- validate_deps(s) == :valid
- end
-
def sorted
rake = @specs.find {|s| s.name == "rake" }
begin
@@ -259,9 +175,8 @@ module Bundler
def lookup
@lookup ||= begin
- lookup = {}
+ lookup = Hash.new {|h, k| h[k] = [] }
@specs.each do |s|
- lookup[s.name] ||= []
lookup[s.name] << s
end
lookup
@@ -275,23 +190,16 @@ module Bundler
def specs_for_dependency(dep, platform)
specs_for_name = lookup[dep.name]
- return [] unless specs_for_name
-
- if platform
- GemHelpers.select_best_platform_match(specs_for_name, platform, force_ruby: dep.force_ruby_platform)
- else
- GemHelpers.select_best_local_platform_match(specs_for_name, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_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
def tsort_each_child(s)
s.dependencies.sort_by(&:name).each do |d|
next if d.type == :development
-
- specs_for_name = lookup[d.name]
- next unless specs_for_name
-
- specs_for_name.each {|s2| yield s2 }
+ lookup[d.name].each {|s2| yield s2 }
end
end
end
diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb
index 718920f091..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
@@ -28,17 +26,6 @@ module Bundler
# @!group Stub Delegates
- def ignored?
- return @ignored unless @ignored.nil?
-
- @ignored = missing_extensions?
- return false unless @ignored
-
- warn "Source #{source} is ignoring #{self} because it is missing extensions"
-
- true
- end
-
def manually_installed?
# This is for manually installed gems which are gems that were fixed in place after a
# failed installation. Once the issue was resolved, the user then manually created
@@ -56,8 +43,8 @@ module Bundler
true
end
- def activated?
- stub.activated?
+ def activated
+ stub.activated
end
def activated=(activated)
@@ -69,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?
@@ -88,14 +75,6 @@ module Bundler
stub.full_require_paths
end
- def require_paths
- stub.require_paths
- end
-
- def base_dir=(path)
- stub.base_dir = path
- end
-
def load_paths
full_require_paths
end
@@ -129,7 +108,6 @@ module Bundler
end
rs.source = source
- rs.base_dir = stub.base_dir
rs
end
diff --git a/lib/bundler/templates/Executable.bundler b/lib/bundler/templates/Executable.bundler
index caa2021701..6dab1688f7 100644
--- a/lib/bundler/templates/Executable.bundler
+++ b/lib/bundler/templates/Executable.bundler
@@ -27,7 +27,7 @@ m = Module.new do
bundler_version = nil
update_index = nil
ARGV.each_with_index do |a, i|
- if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
bundler_version = a
end
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
@@ -47,7 +47,7 @@ m = Module.new do
def lockfile
lockfile =
case File.basename(gemfile)
- when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
else "#{gemfile}.lock"
end
File.expand_path(lockfile)
diff --git a/lib/bundler/templates/gems.rb b/lib/bundler/templates/gems.rb
new file mode 100644
index 0000000000..d2403f18b2
--- /dev/null
+++ b/lib/bundler/templates/gems.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+source "https://rubygems.org"
+
+# gem "rails"
diff --git a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
index 67fe8cee79..175b821a62 100644
--- a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
+++ b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
@@ -2,131 +2,83 @@
## Our Pledge
-We as members, contributors, and leaders pledge to make participation in our
-community a harassment-free experience for everyone, regardless of age, body
-size, visible or invisible disability, ethnicity, sex characteristics, gender
-identity and expression, level of experience, education, socio-economic status,
-nationality, personal appearance, race, caste, color, religion, or sexual
-identity and orientation.
+We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
-We pledge to act and interact in ways that contribute to an open, welcoming,
-diverse, inclusive, and healthy community.
+We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
## Our Standards
-Examples of behavior that contributes to a positive environment for our
-community include:
+Examples of behavior that contributes to a positive environment for our community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
-* Accepting responsibility and apologizing to those affected by our mistakes,
- and learning from the experience
-* Focusing on what is best not just for us as individuals, but for the overall
- community
+* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
-* The use of sexualized language or imagery, and sexual attention or advances of
- any kind
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
-* Publishing others' private information, such as a physical or email address,
- without their explicit permission
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
-Community leaders are responsible for clarifying and enforcing our standards of
-acceptable behavior and will take appropriate and fair corrective action in
-response to any behavior that they deem inappropriate, threatening, offensive,
-or harmful.
+Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
-Community leaders have the right and responsibility to remove, edit, or reject
-comments, commits, code, wiki edits, issues, and other contributions that are
-not aligned to this Code of Conduct, and will communicate reasons for moderation
-decisions when appropriate.
+Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
-This Code of Conduct applies within all community spaces, and also applies when
-an individual is officially representing the community in public spaces.
-Examples of representing our community include using an official email address,
-posting via an official social media account, or acting as an appointed
-representative at an online or offline event.
+This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
## Enforcement
-Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported to the community leaders responsible for enforcement at
-[INSERT CONTACT METHOD].
-All complaints will be reviewed and investigated promptly and fairly.
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at <%= config[:email] %>. All complaints will be reviewed and investigated promptly and fairly.
-All community leaders are obligated to respect the privacy and security of the
-reporter of any incident.
+All community leaders are obligated to respect the privacy and security of the reporter of any incident.
## Enforcement Guidelines
-Community leaders will follow these Community Impact Guidelines in determining
-the consequences for any action they deem in violation of this Code of Conduct:
+Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
-**Community Impact**: Use of inappropriate language or other behavior deemed
-unprofessional or unwelcome in the community.
+**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
-**Consequence**: A private, written warning from community leaders, providing
-clarity around the nature of the violation and an explanation of why the
-behavior was inappropriate. A public apology may be requested.
+**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
### 2. Warning
-**Community Impact**: A violation through a single incident or series of
-actions.
+**Community Impact**: A violation through a single incident or series of actions.
-**Consequence**: A warning with consequences for continued behavior. No
-interaction with the people involved, including unsolicited interaction with
-those enforcing the Code of Conduct, for a specified period of time. This
-includes avoiding interactions in community spaces as well as external channels
-like social media. Violating these terms may lead to a temporary or permanent
-ban.
+**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
### 3. Temporary Ban
-**Community Impact**: A serious violation of community standards, including
-sustained inappropriate behavior.
+**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
-**Consequence**: A temporary ban from any sort of interaction or public
-communication with the community for a specified period of time. No public or
-private interaction with the people involved, including unsolicited interaction
-with those enforcing the Code of Conduct, is allowed during this period.
-Violating these terms may lead to a permanent ban.
+**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
-**Community Impact**: Demonstrating a pattern of violation of community
-standards, including sustained inappropriate behavior, harassment of an
-individual, or aggression toward or disparagement of classes of individuals.
+**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
-**Consequence**: A permanent ban from any sort of public interaction within the
-community.
+**Consequence**: A permanent ban from any sort of public interaction within the community.
## Attribution
-This Code of Conduct is adapted from the [Contributor Covenant][homepage],
-version 2.1, available at
-[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
+available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
-Community Impact Guidelines were inspired by
-[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
-
-For answers to common questions about this code of conduct, see the FAQ at
-[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
-[https://www.contributor-covenant.org/translations][translations].
+Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
-[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
-[Mozilla CoC]: https://github.com/mozilla/diversity
-[FAQ]: https://www.contributor-covenant.org/faq
-[translations]: https://www.contributor-covenant.org/translations
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
diff --git a/lib/bundler/templates/newgem/Gemfile.tt b/lib/bundler/templates/newgem/Gemfile.tt
index a0d2ac2826..41c95677a3 100644
--- a/lib/bundler/templates/newgem/Gemfile.tt
+++ b/lib/bundler/templates/newgem/Gemfile.tt
@@ -10,7 +10,7 @@ gem "rake", "~> 13.0"
gem "rake-compiler"
<%- if config[:ext] == 'rust' -%>
-gem "rb_sys", "~> 0.9.63"
+gem "rb_sys"
<%- end -%>
<%- end -%>
<%- if config[:test] -%>
diff --git a/lib/bundler/templates/newgem/README.md.tt b/lib/bundler/templates/newgem/README.md.tt
index f9c97d5c7e..20eaac8a62 100644
--- a/lib/bundler/templates/newgem/README.md.tt
+++ b/lib/bundler/templates/newgem/README.md.tt
@@ -6,19 +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:
-```bash
-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:
-```bash
-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 172183d4b4..ac14545126 100644
--- a/lib/bundler/templates/newgem/Rakefile.tt
+++ b/lib/bundler/templates/newgem/Rakefile.tt
@@ -4,9 +4,13 @@ require "bundler/gem_tasks"
<% default_task_names = [config[:test_task]].compact -%>
<% case config[:test] -%>
<% when "minitest" -%>
-require "minitest/test_task"
+require "rake/testtask"
-Minitest::TestTask.create
+Rake::TestTask.new(:test) do |t|
+ t.libs << "test"
+ t.libs << "lib"
+ t.test_files = FileList["test/**/test_*.rb"]
+end
<% when "test-unit" -%>
require "rake/testtask"
@@ -37,27 +41,13 @@ require "standard/rake"
<% if config[:ext] -%>
<% default_task_names.unshift(:compile) -%>
<% default_task_names.unshift(:clobber) unless config[:ext] == 'rust' -%>
-<% if config[:ext] == 'rust' -%>
-require "rb_sys/extensiontask"
-
-task build: :compile
-
-GEMSPEC = Gem::Specification.load("<%= config[:underscored_name] %>.gemspec")
-
-RbSys::ExtensionTask.new(<%= config[:name].inspect %>, GEMSPEC) do |ext|
- ext.lib_dir = "lib/<%= config[:namespaced_path] %>"
-end
-<% else -%>
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 -%>
<% end -%>
<% if default_task_names.size == 1 -%>
diff --git a/lib/bundler/templates/newgem/bin/console.tt b/lib/bundler/templates/newgem/bin/console.tt
index c91ee65f93..08dfaaef69 100644
--- a/lib/bundler/templates/newgem/bin/console.tt
+++ b/lib/bundler/templates/newgem/bin/console.tt
@@ -7,5 +7,9 @@ require "<%= config[:namespaced_path] %>"
# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
+# (If you use this, don't forget to add pry to your Gemfile!)
+# require "pry"
+# Pry.start
+
require "irb"
IRB.start(__FILE__)
diff --git a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
index 0ebce0e4a0..4b6e9587f7 100644
--- a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
+++ b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
@@ -12,4 +12,4 @@ publish = false
crate-type = ["cdylib"]
[dependencies]
-magnus = { version = "0.6.2" }
+magnus = { version = "0.4" }
diff --git a/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt b/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt
index 0a0c5a3d09..e918063ddf 100644
--- a/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt
+++ b/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt
@@ -2,9 +2,4 @@
require "mkmf"
-# Makes all symbols private by default to avoid unintended conflict
-# with other gems. To explicitly export symbols you can use RUBY_FUNC_EXPORTED
-# selectively, or entirely remove this flag.
-append_cflags("-fvisibility=hidden")
-
create_makefile(<%= config[:makefile_path].inspect %>)
diff --git a/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt b/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt
index bcd5148569..8177c4d202 100644
--- a/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt
+++ b/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt
@@ -2,7 +2,7 @@
VALUE rb_m<%= config[:constant_array].join %>;
-RUBY_FUNC_EXPORTED void
+void
Init_<%= config[:underscored_name] %>(void)
{
rb_m<%= config[:constant_array].join %> = rb_define_module(<%= config[:constant_name].inspect %>);
diff --git a/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt b/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt
index ba234529a3..b311283997 100644
--- a/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt
+++ b/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt
@@ -1,12 +1,12 @@
-use magnus::{function, prelude::*, Error, Ruby};
+use magnus::{define_module, function, prelude::*, Error};
fn hello(subject: String) -> String {
- format!("Hello from Rust, {subject}!")
+ format!("Hello from Rust, {}!", subject)
}
#[magnus::init]
-fn init(ruby: &Ruby) -> Result<(), Error> {
- let module = ruby.<%= config[:constant_array].map {|c| "define_module(#{c.dump})?"}.join(".") %>;
+fn init() -> Result<(), Error> {
+ let module = <%= config[:constant_array].map {|c| "define_module(#{c.dump})?"}.join(".") %>;
module.define_singleton_method("hello", function!(hello, 1))?;
Ok(())
}
diff --git a/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
index 32b39558d8..d4021980b4 100644
--- a/lib/bundler/templates/newgem/github/workflows/main.yml.tt
+++ b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
@@ -17,10 +17,10 @@ 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
+ uses: oxidize-rb/actions/setup-ruby-and-rust@main
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt
index 6e88f4dab1..e35a121245 100644
--- a/lib/bundler/templates/newgem/newgem.gemspec.tt
+++ b/lib/bundler/templates/newgem/newgem.gemspec.tt
@@ -27,11 +27,9 @@ 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.
- gemspec = File.basename(__FILE__)
- spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
- ls.readlines("\x0", chomp: true).reject do |f|
- (f == gemspec) ||
- f.start_with?(*%w[bin/ test/ spec/ features/ .git <%= config[:ci_config_path] %>appveyor Gemfile])
+ 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)/|\.(?:git|circleci)|appveyor)})
end
end
spec.bindir = "exe"
diff --git a/lib/bundler/templates/newgem/rubocop.yml.tt b/lib/bundler/templates/newgem/rubocop.yml.tt
index 3d1c4ee7b2..9ecec78807 100644
--- a/lib/bundler/templates/newgem/rubocop.yml.tt
+++ b/lib/bundler/templates/newgem/rubocop.yml.tt
@@ -2,7 +2,12 @@ AllCops:
TargetRubyVersion: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %>
Style/StringLiterals:
+ Enabled: true
EnforcedStyle: double_quotes
Style/StringLiteralsInInterpolation:
+ Enabled: true
EnforcedStyle: double_quotes
+
+Layout/LineLength:
+ Max: 120
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/rg_proxy.rb b/lib/bundler/ui/rg_proxy.rb
index b17ca65f53..ef6def225b 100644
--- a/lib/bundler/ui/rg_proxy.rb
+++ b/lib/bundler/ui/rg_proxy.rb
@@ -12,7 +12,7 @@ module Bundler
end
def say(message)
- @ui&.debug(message)
+ @ui && @ui.debug(message)
end
end
end
diff --git a/lib/bundler/ui/shell.rb b/lib/bundler/ui/shell.rb
index 6df1512a5b..4139585c47 100644
--- a/lib/bundler/ui/shell.rb
+++ b/lib/bundler/ui/shell.rb
@@ -6,17 +6,14 @@ module Bundler
module UI
class Shell
LEVELS = %w[silent error warn confirm info debug].freeze
- OUTPUT_STREAMS = [:stdout, :stderr].freeze
attr_writer :shell
- attr_reader :output_stream
def initialize(options = {})
Thor::Base.shell = options["no-color"] ? Thor::Shell::Basic : nil
@shell = Thor::Base.shell.new
@level = ENV["DEBUG"] ? "debug" : "info"
@warning_history = []
- @output_stream = :stdout
end
def add_color(string, *color)
@@ -87,7 +84,7 @@ module Bundler
@shell.yes?(msg)
end
- def no?(msg)
+ def no?
@shell.no?(msg)
end
@@ -104,11 +101,6 @@ module Bundler
index <= LEVELS.index(@level)
end
- def output_stream=(symbol)
- raise ArgumentError unless OUTPUT_STREAMS.include?(symbol)
- @output_stream = symbol
- end
-
def trace(e, newline = nil, force = false)
return unless debug? || force
msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n ")}"
@@ -119,10 +111,6 @@ module Bundler
with_level("silent", &blk)
end
- def progress(&blk)
- with_output_stream(:stderr, &blk)
- end
-
def unprinted_warnings
[]
end
@@ -131,8 +119,6 @@ module Bundler
# valimism
def tell_me(msg, color = nil, newline = nil)
- return tell_err(msg, color, newline) if output_stream == :stderr
-
msg = word_wrap(msg) if newline.is_a?(Hash) && newline[:wrap]
if newline.nil?
@shell.say(msg, color)
@@ -144,7 +130,7 @@ module Bundler
def tell_err(message, color = nil, newline = nil)
return if @shell.send(:stderr).closed?
- newline = !message.to_s.match?(/( |\t)\Z/) if newline.nil?
+ newline ||= message.to_s !~ /( |\t)\Z/
message = word_wrap(message) if newline.is_a?(Hash) && newline[:wrap]
color = nil if color && !$stderr.tty?
@@ -161,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"
@@ -174,14 +160,6 @@ module Bundler
ensure
@level = original
end
-
- def with_output_stream(symbol)
- original = output_stream
- self.output_stream = symbol
- yield
- ensure
- @output_stream = original
- end
end
end
end
diff --git a/lib/bundler/ui/silent.rb b/lib/bundler/ui/silent.rb
index 83d31d4b55..fa3292bdc9 100644
--- a/lib/bundler/ui/silent.rb
+++ b/lib/bundler/ui/silent.rb
@@ -53,13 +53,6 @@ module Bundler
false
end
- def output_stream=(_symbol)
- end
-
- def output_stream
- nil
- end
-
def ask(message)
end
@@ -67,7 +60,7 @@ module Bundler
raise "Cannot ask yes? with a silent shell"
end
- def no?(msg)
+ def no?
raise "Cannot ask no? with a silent shell"
end
@@ -84,10 +77,6 @@ module Bundler
yield
end
- def progress
- yield
- end
-
def unprinted_warnings
@warnings
end
diff --git a/lib/bundler/uri_credentials_filter.rb b/lib/bundler/uri_credentials_filter.rb
index a83f5304e2..ccfaf0bc5d 100644
--- a/lib/bundler/uri_credentials_filter.rb
+++ b/lib/bundler/uri_credentials_filter.rb
@@ -11,7 +11,7 @@ module Bundler
return uri if File.exist?(uri)
require_relative "vendored_uri"
- uri = Gem::URI(uri)
+ uri = Bundler::URI(uri)
end
if uri.userinfo
@@ -25,7 +25,7 @@ module Bundler
end
return uri.to_s if uri_to_anonymize.is_a?(String)
uri
- rescue Gem::URI::InvalidURIError # uri is not canonical uri scheme
+ rescue Bundler::URI::InvalidURIError # uri is not canonical uri scheme
uri
end
diff --git a/lib/bundler/uri_normalizer.rb b/lib/bundler/uri_normalizer.rb
deleted file mode 100644
index ad08593256..0000000000
--- a/lib/bundler/uri_normalizer.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- module URINormalizer
- module_function
-
- # Normalizes uri to a consistent version, either with or without trailing
- # slash.
- #
- # TODO: Currently gem sources are locked with a trailing slash, while git
- # sources are locked without a trailing slash. This should be normalized but
- # the inconsistency is there for now to avoid changing all lockfiles
- # including GIT sources. We could normalize this on the next major.
- #
- def normalize_suffix(uri, trailing_slash: true)
- if trailing_slash
- uri.end_with?("/") ? uri : "#{uri}/"
- else
- uri.end_with?("/") ? uri.delete_suffix("/") : uri
- end
- end
- end
-end
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
index 317088a866..455319efe3 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
@@ -1,4 +1,4 @@
-require_relative "../../../vendored_timeout"
+require "timeout"
require_relative "connection_pool/version"
class Bundler::ConnectionPool
@@ -6,7 +6,7 @@ class Bundler::ConnectionPool
class PoolShuttingDownError < ::Bundler::ConnectionPool::Error; end
- class TimeoutError < ::Gem::Timeout::Error; end
+ class TimeoutError < ::Timeout::Error; end
end
# Generic connection pool class for sharing a limited number of objects or network connections
@@ -36,57 +36,14 @@ end
# Accepts the following options:
# - :size - number of connections to pool, defaults to 5
# - :timeout - amount of time to wait for a connection if none currently available, defaults to 5 seconds
-# - :auto_reload_after_fork - automatically drop all connections after fork, defaults to true
#
class Bundler::ConnectionPool
- DEFAULTS = {size: 5, timeout: 5, auto_reload_after_fork: true}
+ DEFAULTS = {size: 5, timeout: 5}
def self.wrap(options, &block)
Wrapper.new(options, &block)
end
- if Process.respond_to?(:fork)
- INSTANCES = ObjectSpace::WeakMap.new
- private_constant :INSTANCES
-
- def self.after_fork
- INSTANCES.values.each do |pool|
- next unless pool.auto_reload_after_fork
-
- # We're on after fork, so we know all other threads are dead.
- # All we need to do is to ensure the main thread doesn't have a
- # checked out connection
- pool.checkin(force: true)
- pool.reload do |connection|
- # Unfortunately we don't know what method to call to close the connection,
- # so we try the most common one.
- connection.close if connection.respond_to?(:close)
- end
- end
- nil
- end
-
- if ::Process.respond_to?(:_fork) # MRI 3.1+
- module ForkTracker
- def _fork
- pid = super
- if pid == 0
- Bundler::ConnectionPool.after_fork
- end
- pid
- end
- end
- Process.singleton_class.prepend(ForkTracker)
- end
- else
- INSTANCES = nil
- private_constant :INSTANCES
-
- def self.after_fork
- # noop
- end
- end
-
def initialize(options = {}, &block)
raise ArgumentError, "Connection pool requires a block" unless block
@@ -94,12 +51,10 @@ class Bundler::ConnectionPool
@size = Integer(options.fetch(:size))
@timeout = options.fetch(:timeout)
- @auto_reload_after_fork = options.fetch(:auto_reload_after_fork)
@available = TimedStack.new(@size, &block)
@key = :"pool-#{@available.object_id}"
@key_count = :"pool-#{@available.object_id}-count"
- INSTANCES[self] = self if INSTANCES
end
def with(options = {})
@@ -126,16 +81,16 @@ class Bundler::ConnectionPool
end
end
- def checkin(force: false)
+ def checkin
if ::Thread.current[@key]
- if ::Thread.current[@key_count] == 1 || force
+ if ::Thread.current[@key_count] == 1
@available.push(::Thread.current[@key])
::Thread.current[@key] = nil
::Thread.current[@key_count] = nil
else
::Thread.current[@key_count] -= 1
end
- elsif !force
+ else
raise Bundler::ConnectionPool::Error, "no connections are checked out"
end
@@ -162,8 +117,6 @@ class Bundler::ConnectionPool
# Size of this connection pool
attr_reader :size
- # Automatically drop all connections after fork
- attr_reader :auto_reload_after_fork
# Number of pool entries available for checkout at this instant.
def available
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb
index 384d6fc977..56ebf69902 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb
@@ -1,3 +1,3 @@
class Bundler::ConnectionPool
- VERSION = "2.4.1"
+ VERSION = "2.3.0"
end
diff --git a/lib/bundler/vendor/fileutils/lib/fileutils.rb b/lib/bundler/vendor/fileutils/lib/fileutils.rb
index 6db19caf6f..04ac537a28 100644
--- a/lib/bundler/vendor/fileutils/lib/fileutils.rb
+++ b/lib/bundler/vendor/fileutils/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 Bundler::FileUtils
- VERSION = "1.7.2"
+ VERSION = "1.7.0"
def self.private_module_function(name) #:nodoc:
module_function name
@@ -192,6 +192,8 @@ module Bundler::FileUtils
#
# Bundler::FileUtils.pwd # => "/rdoc/fileutils"
#
+ # Bundler::FileUtils.getwd is an alias for Bundler::FileUtils.pwd.
+ #
# Related: Bundler::FileUtils.cd.
#
def pwd
@@ -233,6 +235,8 @@ module Bundler::FileUtils
# cd ..
# cd fileutils
#
+ # Bundler::FileUtils.chdir is an alias for Bundler::FileUtils.cd.
+ #
# Related: Bundler::FileUtils.pwd.
#
def cd(dir, verbose: nil, &block) # :yield: dir
@@ -511,6 +515,8 @@ module Bundler::FileUtils
# Raises an exception if +dest+ is the path to an existing file
# and keyword argument +force+ is not +true+.
#
+ # Bundler::FileUtils#link is an alias for Bundler::FileUtils#ln.
+ #
# Related: Bundler::FileUtils.link_entry (has different options).
#
def ln(src, dest, force: nil, noop: nil, verbose: nil)
@@ -701,6 +707,8 @@ module Bundler::FileUtils
# ln -sf src2.txt dest2.txt
# ln -s srcdir3/src0.txt srcdir3/src1.txt destdir3
#
+ # Bundler::FileUtils.symlink is an alias for Bundler::FileUtils.ln_s.
+ #
# Related: Bundler::FileUtils.ln_sf.
#
def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
@@ -868,6 +876,8 @@ module Bundler::FileUtils
#
# Raises an exception if +src+ is a directory.
#
+ # Bundler::FileUtils.copy is an alias for Bundler::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 Bundler::FileUtils
# mv src0 dest0
# mv src1.txt src1 dest1
#
+ # Bundler::FileUtils.move is an alias for Bundler::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 Bundler::FileUtils
#
# rm src0.dat src0.txt
#
+ # Bundler::FileUtils.remove is an alias for Bundler::FileUtils.rm.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm(list, force: nil, noop: nil, verbose: nil)
@@ -1236,6 +1250,8 @@ module Bundler::FileUtils
#
# See Bundler::FileUtils.rm for keyword arguments.
#
+ # Bundler::FileUtils.safe_unlink is an alias for Bundler::FileUtils.rm_f.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_f(list, noop: nil, verbose: nil)
@@ -1323,6 +1339,8 @@ module Bundler::FileUtils
#
# See Bundler::FileUtils.rm_r for keyword arguments.
#
+ # Bundler::FileUtils.rmtree is an alias for Bundler::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 Bundler::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/bundler/vendor/net-http-persistent/.document b/lib/bundler/vendor/net-http-persistent/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/net-http-persistent/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
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 cfc0f48197..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
@@ -1,14 +1,14 @@
-require_relative '../../../../../vendored_net_http'
-require_relative '../../../../../vendored_uri'
+require 'net/http'
+require_relative '../../../../uri/lib/uri'
require 'cgi' # for escaping
require_relative '../../../../connection_pool/lib/connection_pool'
autoload :OpenSSL, 'openssl'
##
-# Persistent connections for Gem::Net::HTTP
+# Persistent connections for Net::HTTP
#
-# Gem::Net::HTTP::Persistent maintains persistent connections across all the
+# Bundler::Persistent::Net::HTTP::Persistent maintains persistent connections across all the
# servers you wish to talk to. For each host:port you communicate with a
# single persistent connection is created.
#
@@ -22,34 +22,34 @@ autoload :OpenSSL, 'openssl'
#
# require 'bundler/vendor/net-http-persistent/lib/net/http/persistent'
#
-# uri = Gem::URI 'http://example.com/awesome/web/service'
+# uri = Bundler::URI 'http://example.com/awesome/web/service'
#
-# http = Gem::Net::HTTP::Persistent.new
+# http = Bundler::Persistent::Net::HTTP::Persistent.new
#
# # perform a GET
# response = http.request uri
#
# # or
#
-# get = Gem::Net::HTTP::Get.new uri.request_uri
+# get = Net::HTTP::Get.new uri.request_uri
# response = http.request get
#
# # create a POST
# post_uri = uri + 'create'
-# post = Gem::Net::HTTP::Post.new post_uri.path
+# post = Net::HTTP::Post.new post_uri.path
# post.set_form_data 'some' => 'cool data'
#
-# # perform the POST, the Gem::URI is always required
+# # perform the POST, the Bundler::URI is always required
# response http.request post_uri, post
#
# Note that for GET, HEAD and other requests that do not have a body you want
-# to use Gem::URI#request_uri not Gem::URI#path. The request_uri contains the query
+# to use Bundler::URI#request_uri not Bundler::URI#path. The request_uri contains the query
# params which are sent in the body for other requests.
#
# == TLS/SSL
#
# TLS connections are automatically created depending upon the scheme of the
-# Gem::URI. TLS connections are automatically verified against the default
+# Bundler::URI. TLS connections are automatically verified against the default
# certificate store for your computer. You can override this by changing
# verify_mode or by specifying an alternate cert_store.
#
@@ -68,13 +68,11 @@ autoload :OpenSSL, 'openssl'
# #verify_callback :: For server certificate verification
# #verify_depth :: Depth of certificate verification
# #verify_mode :: How connections should be verified
-# #verify_hostname :: Use hostname verification for server certificate
-# during the handshake
#
# == Proxies
#
# A proxy can be set through #proxy= or at initialization time by providing a
-# second argument to ::new. The proxy may be the Gem::URI of the proxy server or
+# second argument to ::new. The proxy may be the Bundler::URI of the proxy server or
# <code>:ENV</code> which will consult environment variables.
#
# See #proxy= and #proxy_from_env for details.
@@ -94,7 +92,7 @@ autoload :OpenSSL, 'openssl'
#
# === Segregation
#
-# Each Gem::Net::HTTP::Persistent instance has its own pool of connections. There
+# Each Bundler::Persistent::Net::HTTP::Persistent instance has its own pool of connections. There
# is no sharing with other instances (as was true in earlier versions).
#
# === Idle Timeout
@@ -133,7 +131,7 @@ autoload :OpenSSL, 'openssl'
#
# === Connection Termination
#
-# If you are done using the Gem::Net::HTTP::Persistent instance you may shut down
+# If you are done using the Bundler::Persistent::Net::HTTP::Persistent instance you may shut down
# all the connections in the current thread with #shutdown. This is not
# recommended for normal use, it should only be used when it will be several
# minutes before you make another HTTP request.
@@ -143,7 +141,7 @@ autoload :OpenSSL, 'openssl'
# Ruby will automatically garbage collect and shutdown your HTTP connections
# when the thread terminates.
-class Gem::Net::HTTP::Persistent
+class Bundler::Persistent::Net::HTTP::Persistent
##
# The beginning of Time
@@ -174,12 +172,12 @@ class Gem::Net::HTTP::Persistent
end
##
- # The version of Gem::Net::HTTP::Persistent you are using
+ # The version of Bundler::Persistent::Net::HTTP::Persistent you are using
- VERSION = '4.0.4'
+ VERSION = '4.0.1'
##
- # Error class for errors raised by Gem::Net::HTTP::Persistent. Various
+ # Error class for errors raised by Bundler::Persistent::Net::HTTP::Persistent. Various
# SystemCallErrors are re-raised with a human-readable message under this
# class.
@@ -199,10 +197,10 @@ class Gem::Net::HTTP::Persistent
# NOTE: This may not work on ruby > 1.9.
def self.detect_idle_timeout uri, max = 10
- uri = Gem::URI uri unless Gem::URI::Generic === uri
+ uri = Bundler::URI uri unless Bundler::URI::Generic === uri
uri += '/'
- req = Gem::Net::HTTP::Head.new uri.request_uri
+ req = Net::HTTP::Head.new uri.request_uri
http = new 'net-http-persistent detect_idle_timeout'
@@ -216,7 +214,7 @@ class Gem::Net::HTTP::Persistent
$stderr.puts "HEAD #{uri} => #{response.code}" if $DEBUG
- unless Gem::Net::HTTPOK === response then
+ unless Net::HTTPOK === response then
raise Error, "bad response code #{response.code} detecting idle timeout"
end
@@ -240,7 +238,7 @@ class Gem::Net::HTTP::Persistent
attr_reader :certificate
##
- # For Gem::Net::HTTP parity
+ # For Net::HTTP parity
alias cert certificate
@@ -268,7 +266,7 @@ class Gem::Net::HTTP::Persistent
attr_reader :ciphers
##
- # Sends debug_output to this IO via Gem::Net::HTTP#set_debug_output.
+ # Sends debug_output to this IO via Net::HTTP#set_debug_output.
#
# Never use this method in production code, it causes a serious security
# hole.
@@ -281,7 +279,7 @@ class Gem::Net::HTTP::Persistent
attr_reader :generation # :nodoc:
##
- # Headers that are added to every request using Gem::Net::HTTP#add_field
+ # Headers that are added to every request using Net::HTTP#add_field
attr_reader :headers
@@ -306,7 +304,7 @@ class Gem::Net::HTTP::Persistent
##
# Number of retries to perform if a request fails.
#
- # See also #max_retries=, Gem::Net::HTTP#max_retries=.
+ # See also #max_retries=, Net::HTTP#max_retries=.
attr_reader :max_retries
@@ -327,12 +325,12 @@ class Gem::Net::HTTP::Persistent
attr_reader :name
##
- # Seconds to wait until a connection is opened. See Gem::Net::HTTP#open_timeout
+ # Seconds to wait until a connection is opened. See Net::HTTP#open_timeout
attr_accessor :open_timeout
##
- # Headers that are added to every request using Gem::Net::HTTP#[]=
+ # Headers that are added to every request using Net::HTTP#[]=
attr_reader :override_headers
@@ -342,7 +340,7 @@ class Gem::Net::HTTP::Persistent
attr_reader :private_key
##
- # For Gem::Net::HTTP parity
+ # For Net::HTTP parity
alias key private_key
@@ -362,12 +360,12 @@ class Gem::Net::HTTP::Persistent
attr_reader :pool # :nodoc:
##
- # Seconds to wait until reading one block. See Gem::Net::HTTP#read_timeout
+ # Seconds to wait until reading one block. See Net::HTTP#read_timeout
attr_accessor :read_timeout
##
- # Seconds to wait until writing one block. See Gem::Net::HTTP#write_timeout
+ # Seconds to wait until writing one block. See Net::HTTP#write_timeout
attr_accessor :write_timeout
@@ -452,33 +450,18 @@ class Gem::Net::HTTP::Persistent
attr_reader :verify_mode
##
- # HTTPS verify_hostname.
- #
- # If a client sets this to true and enables SNI with SSLSocket#hostname=,
- # the hostname verification on the server certificate is performed
- # automatically during the handshake using
- # OpenSSL::SSL.verify_certificate_identity().
- #
- # You can set +verify_hostname+ as true to use hostname verification
- # during the handshake.
- #
- # NOTE: This works with Ruby > 3.0.
-
- attr_reader :verify_hostname
-
- ##
- # Creates a new Gem::Net::HTTP::Persistent.
+ # Creates a new Bundler::Persistent::Net::HTTP::Persistent.
#
# Set a +name+ for fun. Your library name should be good enough, but this
# otherwise has no purpose.
#
- # +proxy+ may be set to a Gem::URI::HTTP or :ENV to pick up proxy options from
+ # +proxy+ may be set to a Bundler::URI::HTTP or :ENV to pick up proxy options from
# the environment. See proxy_from_env for details.
#
- # In order to use a Gem::URI for the proxy you may need to do some extra work
- # beyond Gem::URI parsing if the proxy requires a password:
+ # In order to use a Bundler::URI for the proxy you may need to do some extra work
+ # beyond Bundler::URI parsing if the proxy requires a password:
#
- # proxy = Gem::URI 'http://proxy.example'
+ # proxy = Bundler::URI 'http://proxy.example'
# proxy.user = 'AzureDiamond'
# proxy.password = 'hunter2'
#
@@ -509,8 +492,8 @@ class Gem::Net::HTTP::Persistent
@socket_options << [Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1] if
Socket.const_defined? :TCP_NODELAY
- @pool = Gem::Net::HTTP::Persistent::Pool.new size: pool_size do |http_args|
- Gem::Net::HTTP::Persistent::Connection.new Gem::Net::HTTP, http_args, @ssl_generation
+ @pool = Bundler::Persistent::Net::HTTP::Persistent::Pool.new size: pool_size do |http_args|
+ Bundler::Persistent::Net::HTTP::Persistent::Connection.new Net::HTTP, http_args, @ssl_generation
end
@certificate = nil
@@ -525,10 +508,9 @@ class Gem::Net::HTTP::Persistent
@verify_callback = nil
@verify_depth = nil
@verify_mode = nil
- @verify_hostname = nil
@cert_store = nil
- @generation = 0 # incremented when proxy Gem::URI changes
+ @generation = 0 # incremented when proxy Bundler::URI changes
if HAVE_OPENSSL then
@verify_mode = OpenSSL::SSL::VERIFY_PEER
@@ -547,7 +529,7 @@ class Gem::Net::HTTP::Persistent
reconnect_ssl
end
- # For Gem::Net::HTTP parity
+ # For Net::HTTP parity
alias cert= certificate=
##
@@ -625,23 +607,13 @@ class Gem::Net::HTTP::Persistent
return yield connection
rescue Errno::ECONNREFUSED
- if http.proxy?
- address = http.proxy_address
- port = http.proxy_port
- else
- address = http.address
- port = http.port
- end
+ address = http.proxy_address || http.address
+ port = http.proxy_port || http.port
raise Error, "connection refused: #{address}:#{port}"
rescue Errno::EHOSTDOWN
- if http.proxy?
- address = http.proxy_address
- port = http.proxy_port
- else
- address = http.address
- port = http.port
- end
+ address = http.proxy_address || http.address
+ port = http.proxy_port || http.port
raise Error, "host down: #{address}:#{port}"
ensure
@@ -676,7 +648,7 @@ class Gem::Net::HTTP::Persistent
end
##
- # Starts the Gem::Net::HTTP +connection+
+ # Starts the Net::HTTP +connection+
def start http
http.set_debug_output @debug_output if @debug_output
@@ -694,7 +666,7 @@ class Gem::Net::HTTP::Persistent
end
##
- # Finishes the Gem::Net::HTTP +connection+
+ # Finishes the Net::HTTP +connection+
def finish connection
connection.finish
@@ -744,16 +716,16 @@ class Gem::Net::HTTP::Persistent
reconnect_ssl
end
- # For Gem::Net::HTTP parity
+ # For Net::HTTP parity
alias key= private_key=
##
- # Sets the proxy server. The +proxy+ may be the Gem::URI of the proxy server,
+ # Sets the proxy server. The +proxy+ may be the Bundler::URI of the proxy server,
# the symbol +:ENV+ which will read the proxy from the environment or nil to
# disable use of a proxy. See #proxy_from_env for details on setting the
# proxy from the environment.
#
- # If the proxy Gem::URI is set after requests have been made, the next request
+ # If the proxy Bundler::URI is set after requests have been made, the next request
# will shut-down and re-open all connections.
#
# The +no_proxy+ query parameter can be used to specify hosts which shouldn't
@@ -764,9 +736,9 @@ class Gem::Net::HTTP::Persistent
def proxy= proxy
@proxy_uri = case proxy
when :ENV then proxy_from_env
- when Gem::URI::HTTP then proxy
+ when Bundler::URI::HTTP then proxy
when nil then # ignore
- else raise ArgumentError, 'proxy must be :ENV or a Gem::URI::HTTP'
+ else raise ArgumentError, 'proxy must be :ENV or a Bundler::URI::HTTP'
end
@no_proxy.clear
@@ -791,13 +763,13 @@ class Gem::Net::HTTP::Persistent
end
##
- # Creates a Gem::URI for an HTTP proxy server from ENV variables.
+ # Creates a Bundler::URI for an HTTP proxy server from ENV variables.
#
# If +HTTP_PROXY+ is set a proxy will be returned.
#
- # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the Gem::URI is given the
+ # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the Bundler::URI is given the
# indicated user and password unless HTTP_PROXY contains either of these in
- # the Gem::URI.
+ # the Bundler::URI.
#
# The +NO_PROXY+ ENV variable can be used to specify hosts which shouldn't
# be reached via proxy; if set it should be a comma separated list of
@@ -813,7 +785,7 @@ class Gem::Net::HTTP::Persistent
return nil if env_proxy.nil? or env_proxy.empty?
- uri = Gem::URI normalize_uri env_proxy
+ uri = Bundler::URI normalize_uri env_proxy
env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
@@ -863,7 +835,7 @@ class Gem::Net::HTTP::Persistent
end
##
- # Finishes then restarts the Gem::Net::HTTP +connection+
+ # Finishes then restarts the Net::HTTP +connection+
def reset connection
http = connection.http
@@ -882,16 +854,16 @@ class Gem::Net::HTTP::Persistent
end
##
- # Makes a request on +uri+. If +req+ is nil a Gem::Net::HTTP::Get is performed
+ # Makes a request on +uri+. If +req+ is nil a Net::HTTP::Get is performed
# against +uri+.
#
- # If a block is passed #request behaves like Gem::Net::HTTP#request (the body of
+ # If a block is passed #request behaves like Net::HTTP#request (the body of
# the response will not have been read).
#
- # +req+ must be a Gem::Net::HTTPGenericRequest subclass (see Gem::Net::HTTP for a list).
+ # +req+ must be a Net::HTTPGenericRequest subclass (see Net::HTTP for a list).
def request uri, req = nil, &block
- uri = Gem::URI uri
+ uri = Bundler::URI uri
req = request_setup req || uri
response = nil
@@ -924,14 +896,14 @@ class Gem::Net::HTTP::Persistent
end
##
- # Creates a GET request if +req_or_uri+ is a Gem::URI and adds headers to the
+ # Creates a GET request if +req_or_uri+ is a Bundler::URI and adds headers to the
# request.
#
# Returns the request.
def request_setup req_or_uri # :nodoc:
req = if req_or_uri.respond_to? 'request_uri' then
- Gem::Net::HTTP::Get.new req_or_uri.request_uri
+ Net::HTTP::Get.new req_or_uri.request_uri
else
req_or_uri
end
@@ -976,10 +948,8 @@ class Gem::Net::HTTP::Persistent
connection.min_version = @min_version if @min_version
connection.max_version = @max_version if @max_version
- connection.verify_depth = @verify_depth
- connection.verify_mode = @verify_mode
- connection.verify_hostname = @verify_hostname if
- @verify_hostname != nil && connection.respond_to?(:verify_hostname=)
+ connection.verify_depth = @verify_depth
+ connection.verify_mode = @verify_mode
if OpenSSL::SSL::VERIFY_PEER == OpenSSL::SSL::VERIFY_NONE and
not Object.const_defined?(:I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG) then
@@ -1089,15 +1059,6 @@ application:
end
##
- # Sets the HTTPS verify_hostname.
-
- def verify_hostname= verify_hostname
- @verify_hostname = verify_hostname
-
- reconnect_ssl
- end
-
- ##
# SSL verification callback.
def verify_callback= callback
@@ -1109,3 +1070,4 @@ end
require_relative 'persistent/connection'
require_relative 'persistent/pool'
+
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 8b9ab5cc78..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
@@ -1,8 +1,8 @@
##
-# A Gem::Net::HTTP connection wrapper that holds extra information for managing the
+# A Net::HTTP connection wrapper that holds extra information for managing the
# connection's lifetime.
-class Gem::Net::HTTP::Persistent::Connection # :nodoc:
+class Bundler::Persistent::Net::HTTP::Persistent::Connection # :nodoc:
attr_accessor :http
@@ -25,10 +25,9 @@ class Gem::Net::HTTP::Persistent::Connection # :nodoc:
ensure
reset
end
- alias_method :close, :finish
def reset
- @last_use = Gem::Net::HTTP::Persistent::EPOCH
+ @last_use = Bundler::Persistent::Net::HTTP::Persistent::EPOCH
@requests = 0
end
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 04a1e754bf..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
@@ -1,4 +1,4 @@
-class Gem::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc:
+class Bundler::Persistent::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc:
attr_reader :available # :nodoc:
attr_reader :key # :nodoc:
@@ -6,37 +6,25 @@ class Gem::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc:
def initialize(options = {}, &block)
super
- @available = Gem::Net::HTTP::Persistent::TimedStackMulti.new(@size, &block)
+ @available = Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti.new(@size, &block)
@key = "current-#{@available.object_id}"
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/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb
index 214804fcd9..2da881c554 100644
--- a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb
@@ -1,4 +1,4 @@
-class Gem::Net::HTTP::Persistent::TimedStackMulti < Bundler::ConnectionPool::TimedStack # :nodoc:
+class Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti < Bundler::ConnectionPool::TimedStack # :nodoc:
##
# Returns a new hash that has arrays for keys
diff --git a/lib/bundler/vendor/pub_grub/.document b/lib/bundler/vendor/pub_grub/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/pub_grub/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb
index 239eaf3401..dab58ecdf7 100644
--- a/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb
+++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb
@@ -8,6 +8,9 @@ module Bundler::PubGrub
InvalidDependency = Struct.new(:package, :constraint) do
end
+ CircularDependency = Struct.new(:package, :constraint) do
+ end
+
NoVersions = Struct.new(:constraint) do
end
@@ -63,6 +66,8 @@ module Bundler::PubGrub
"#{terms[0].to_s(allow_every: true)} depends on #{terms[1].invert}"
when Bundler::PubGrub::Incompatibility::InvalidDependency
"#{terms[0].to_s(allow_every: true)} depends on unknown package #{cause.package}"
+ when Bundler::PubGrub::Incompatibility::CircularDependency
+ "#{terms[0].to_s(allow_every: true)} depends on itself"
when Bundler::PubGrub::Incompatibility::NoVersions
"no versions satisfy #{cause.constraint}"
when Bundler::PubGrub::Incompatibility::ConflictCause
@@ -71,13 +76,9 @@ module Bundler::PubGrub
elsif terms.length == 1
term = terms[0]
if term.positive?
- if term.constraint.any?
- "#{term.package} cannot be used"
- else
- "#{term.to_s(allow_every: true)} cannot be used"
- end
+ "#{terms[0].to_s(allow_every: true)} is forbidden"
else
- "#{term.invert} is required"
+ "#{terms[0].invert} is required"
end
else
if terms.all?(&:positive?)
diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb
index 36ab06254d..e895812bed 100644
--- a/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb
+++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb
@@ -1,5 +1,4 @@
require_relative 'package'
-require_relative 'rubygems'
require_relative 'version_constraint'
require_relative 'incompatibility'
require_relative 'basic_package_source'
@@ -20,14 +19,7 @@ module Bundler::PubGrub
version = Gem::Version.new(version)
@packages[name] ||= {}
raise ArgumentError, "#{name} #{version} declared twice" if @packages[name].key?(version)
- @packages[name][version] = clean_deps(name, version, deps)
- end
-
- private
-
- # Exclude redundant self-referencing dependencies
- def clean_deps(name, version, deps)
- deps.reject {|dep_name, req| name == dep_name && Bundler::PubGrub::RubyGems.parse_range(req).include?(version) }
+ @packages[name][version] = deps
end
end
diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb
index b71f3eaf53..9133332d01 100644
--- a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb
+++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb
@@ -15,16 +15,15 @@ module Bundler::PubGrub
package.hash ^ range.hash
end
- def ==(other)
- package == other.package &&
- range == other.range
- end
-
def eql?(other)
package.eql?(other.package) &&
range.eql?(other.range)
end
+ def ==(other)
+ package == other.package && range == other.range
+ end
+
class << self
def exact(package, version)
range = VersionRange.new(min: version, max: version, include_min: true, include_max: true)
diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb
index 8d73c3f7b5..506b447b36 100644
--- a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb
+++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb
@@ -19,7 +19,7 @@ module Bundler::PubGrub
true
end
- def eql?(other)
+ def eql?
other.empty?
end
@@ -65,7 +65,6 @@ module Bundler::PubGrub
end
EMPTY = Empty.new
- Empty.singleton_class.undef_method(:new)
def self.empty
EMPTY
@@ -89,8 +88,7 @@ module Bundler::PubGrub
def eql?(other)
if other.is_a?(VersionRange)
- !other.empty? &&
- min.eql?(other.min) &&
+ min.eql?(other.min) &&
max.eql?(other.max) &&
include_min.eql?(other.include_min) &&
include_max.eql?(other.include_max)
diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb
index 4caf6b355b..ea5e455968 100644
--- a/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb
+++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb
@@ -125,7 +125,6 @@ module Bundler::PubGrub
package = next_package_to_try
unsatisfied_term = solution.unsatisfied.find { |t| t.package == package }
version = source.versions_for(package, unsatisfied_term.constraint.range).first
- logger.debug { "attempting #{package} #{version}" }
if version.nil?
add_incompatibility source.no_versions_incompatibility_for(package, unsatisfied_term)
@@ -149,11 +148,9 @@ module Bundler::PubGrub
end
unless conflict
- logger.info { "selected #{package} #{version}" }
+ logger.info { "selecting #{package} #{version}" }
solution.decide(package, version)
- else
- logger.info { "conflict: #{conflict.inspect}" }
end
package
@@ -162,7 +159,7 @@ module Bundler::PubGrub
def resolve_conflict(incompatibility)
logger.info { "conflict: #{incompatibility}" }
- new_incompatibility = nil
+ new_incompatibility = false
while !incompatibility.failure?
most_recent_term = nil
@@ -204,7 +201,7 @@ module Bundler::PubGrub
solution.backtrack(previous_level)
if new_incompatibility
- add_incompatibility(new_incompatibility)
+ add_incompatibility(incompatibility)
end
return incompatibility
@@ -219,14 +216,9 @@ module Bundler::PubGrub
new_terms << difference.invert
end
- new_incompatibility = Incompatibility.new(new_terms, cause: Incompatibility::ConflictCause.new(incompatibility, most_recent_satisfier.cause))
-
- if incompatibility.to_s == new_incompatibility.to_s
- logger.info { "!! failed to resolve conflicts, this shouldn't have happened" }
- break
- end
+ incompatibility = Incompatibility.new(new_terms, cause: Incompatibility::ConflictCause.new(incompatibility, most_recent_satisfier.cause))
- incompatibility = new_incompatibility
+ new_incompatibility = true
partially = difference ? " partially" : ""
logger.info { "! #{most_recent_term} is#{partially} satisfied by #{most_recent_satisfier.term}" }
diff --git a/lib/bundler/vendor/securerandom/.document b/lib/bundler/vendor/securerandom/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/securerandom/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/securerandom/lib/random/formatter.rb b/lib/bundler/vendor/securerandom/lib/random/formatter.rb
deleted file mode 100644
index e429709789..0000000000
--- a/lib/bundler/vendor/securerandom/lib/random/formatter.rb
+++ /dev/null
@@ -1,373 +0,0 @@
-# -*- coding: us-ascii -*-
-# frozen_string_literal: true
-
-# == \Random number formatter.
-#
-# Formats generated random numbers in many manners. When <tt>'random/formatter'</tt>
-# is required, several methods are added to empty core module <tt>Bundler::Random::Formatter</tt>,
-# making them available as Random's instance and module methods.
-#
-# Standard library Bundler::SecureRandom is also extended with the module, and the methods
-# described below are available as a module methods in it.
-#
-# === Examples
-#
-# Generate random hexadecimal strings:
-#
-# require 'bundler/vendor/securerandom/lib/random/formatter'
-#
-# prng = Random.new
-# prng.hex(10) #=> "52750b30ffbc7de3b362"
-# prng.hex(10) #=> "92b15d6c8dc4beb5f559"
-# prng.hex(13) #=> "39b290146bea6ce975c37cfc23"
-# # or just
-# Random.hex #=> "1aed0c631e41be7f77365415541052ee"
-#
-# Generate random base64 strings:
-#
-# prng.base64(10) #=> "EcmTPZwWRAozdA=="
-# prng.base64(10) #=> "KO1nIU+p9DKxGg=="
-# prng.base64(12) #=> "7kJSM/MzBJI+75j8"
-# Random.base64(4) #=> "bsQ3fQ=="
-#
-# Generate random binary strings:
-#
-# prng.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
-# prng.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
-# Random.random_bytes(6) #=> "\xA1\xE6Lr\xC43"
-#
-# Generate alphanumeric strings:
-#
-# prng.alphanumeric(10) #=> "S8baxMJnPl"
-# prng.alphanumeric(10) #=> "aOxAg8BAJe"
-# Random.alphanumeric #=> "TmP9OsJHJLtaZYhP"
-#
-# Generate UUIDs:
-#
-# prng.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
-# prng.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
-# Random.uuid #=> "f14e0271-de96-45cc-8911-8910292a42cd"
-#
-# All methods are available in the standard library Bundler::SecureRandom, too:
-#
-# Bundler::SecureRandom.hex #=> "05b45376a30c67238eb93b16499e50cf"
-
-module Bundler::Random::Formatter
-
- # Generate a random binary string.
- #
- # The argument _n_ specifies the length of the result string.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in future.
- #
- # The result may contain any byte: "\x00" - "\xff".
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6"
- # # or
- # prng = Random.new
- # prng.random_bytes #=> "m\xDC\xFC/\a\x00Uf\xB2\xB2P\xBD\xFF6S\x97"
- def random_bytes(n=nil)
- n = n ? n.to_int : 16
- gen_random(n)
- end
-
- # Generate a random hexadecimal string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number to be generated.
- # The length of the resulting hexadecimal string is twice of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The result may contain 0-9 and a-f.
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"
- # # or
- # prng = Random.new
- # prng.hex #=> "91dc3bfb4de5b11d029d376634589b61"
- def hex(n=nil)
- random_bytes(n).unpack1("H*")
- end
-
- # Generate a random base64 string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number
- # to be generated. The length of the result string is about 4/3 of _n_.
- #
- # 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, 0-9, "+", "/" and "=".
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A=="
- # # or
- # prng = Random.new
- # prng.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
- #
- # See RFC 3548 for the definition of base64.
- def base64(n=nil)
- [random_bytes(n)].pack("m0")
- end
-
- # Generate a random URL-safe base64 string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number
- # to be generated. The length of the result string is about 4/3 of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The boolean argument _padding_ specifies the padding.
- # If it is false or nil, padding is not generated.
- # Otherwise padding is generated.
- # By default, padding is not generated because "=" may be used as a URL delimiter.
- #
- # The result may contain A-Z, a-z, 0-9, "-" and "_".
- # "=" is also used if _padding_ is true.
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg"
- # # or
- # prng = Random.new
- # prng.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
- #
- # prng.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
- # prng.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="
- #
- # See RFC 3548 for the definition of URL-safe base64.
- def urlsafe_base64(n=nil, padding=false)
- s = [random_bytes(n)].pack("m0")
- s.tr!("+/", "-_")
- s.delete!("=") unless padding
- s
- end
-
- # Generate a random v4 UUID (Universally Unique IDentifier).
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
- # Random.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
- # # or
- # prng = Random.new
- # prng.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"
- #
- # The version 4 UUID is purely random (except the version).
- # It doesn't contain meaningful information such as MAC addresses, timestamps, etc.
- #
- # The result contains 122 random bits (15.25 random bytes).
- #
- # See RFC4122[https://datatracker.ietf.org/doc/html/rfc4122] for details of UUID.
- #
- def uuid
- ary = random_bytes(16).unpack("NnnnnN")
- ary[2] = (ary[2] & 0x0fff) | 0x4000
- ary[3] = (ary[3] & 0x3fff) | 0x8000
- "%08x-%04x-%04x-%04x-%04x%08x" % ary
- end
-
- alias uuid_v4 uuid
-
- # Generate a random v7 UUID (Universally Unique IDentifier).
- #
- # require 'bundler/vendor/securerandom/lib/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 because its output
- # includes not only random bits but also timestamp.
- #
- # 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
-
- # Internal interface to Random; Generate random data _n_ bytes.
- private def gen_random(n)
- self.bytes(n)
- end
-
- # Generate a string that randomly draws from a
- # source array of characters.
- #
- # The argument _source_ specifies the array of characters from which
- # to generate the string.
- # The argument _n_ specifies the length, in characters, of the string to be
- # generated.
- #
- # The result may contain whatever characters are in the source array.
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # prng.choose([*'l'..'r'], 16) #=> "lmrqpoonmmlqlron"
- # prng.choose([*'0'..'9'], 5) #=> "27309"
- private def choose(source, n)
- size = source.size
- m = 1
- limit = size
- while limit * size <= 0x100000000
- limit *= size
- m += 1
- end
- result = ''.dup
- while m <= n
- rs = random_number(limit)
- is = rs.digits(size)
- (m-is.length).times { is << 0 }
- result << source.values_at(*is).join('')
- n -= m
- end
- if 0 < n
- rs = random_number(limit)
- is = rs.digits(size)
- if is.length < n
- (n-is.length).times { is << 0 }
- else
- is.pop while n < is.length
- end
- result.concat source.values_at(*is).join('')
- end
- result
- end
-
- # The default character list for #alphanumeric.
- ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
-
- # Generate a random alphanumeric string.
- #
- # 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.
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.alphanumeric #=> "2BuBuLf3WfSKyQbR"
- # # 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)
- n = 16 if n.nil?
- choose(chars, n)
- end
-end
diff --git a/lib/bundler/vendor/securerandom/lib/securerandom.rb b/lib/bundler/vendor/securerandom/lib/securerandom.rb
deleted file mode 100644
index e797054468..0000000000
--- a/lib/bundler/vendor/securerandom/lib/securerandom.rb
+++ /dev/null
@@ -1,96 +0,0 @@
-# -*- coding: us-ascii -*-
-# frozen_string_literal: true
-
-require_relative 'random/formatter'
-
-# == Secure random number generator interface.
-#
-# This library is an interface to secure random number generators which are
-# suitable for generating session keys in HTTP cookies, etc.
-#
-# You can use this library in your application by requiring it:
-#
-# require 'bundler/vendor/securerandom/lib/securerandom'
-#
-# It supports the following secure random number generators:
-#
-# * openssl
-# * /dev/urandom
-# * Win32
-#
-# Bundler::SecureRandom is extended by the Bundler::Random::Formatter module which
-# defines the following methods:
-#
-# * alphanumeric
-# * base64
-# * choose
-# * gen_random
-# * hex
-# * rand
-# * random_bytes
-# * random_number
-# * urlsafe_base64
-# * uuid
-#
-# These methods are usable as class methods of Bundler::SecureRandom such as
-# +Bundler::SecureRandom.hex+.
-#
-# If a secure random number generator is not available,
-# +NotImplementedError+ is raised.
-
-module Bundler::SecureRandom
-
- # The version
- VERSION = "0.3.1"
-
- class << self
- # Returns a random binary string containing +size+ bytes.
- #
- # See Random.bytes
- def bytes(n)
- return gen_random(n)
- end
-
- private
-
- # :stopdoc:
-
- # Implementation using OpenSSL
- def gen_random_openssl(n)
- return OpenSSL::Random.random_bytes(n)
- end
-
- # Implementation using system random device
- def gen_random_urandom(n)
- ret = Random.urandom(n)
- unless ret
- raise NotImplementedError, "No random device"
- end
- unless ret.length == n
- raise NotImplementedError, "Unexpected partial read from random device: only #{ret.length} for #{n} bytes"
- end
- ret
- end
-
- begin
- # Check if Random.urandom is available
- Random.urandom(1)
- alias gen_random gen_random_urandom
- rescue RuntimeError
- begin
- require 'openssl'
- rescue NoMethodError
- raise NotImplementedError, "No random device"
- else
- alias gen_random gen_random_openssl
- end
- end
-
- # :startdoc:
-
- # Generate random data bytes for Bundler::Random::Formatter
- public :gen_random
- end
-end
-
-Bundler::SecureRandom.extend(Bundler::Random::Formatter)
diff --git a/lib/bundler/vendor/thor/.document b/lib/bundler/vendor/thor/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/thor/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
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 5d708fadca..dc167ed3cc 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell/color.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell/color.rb
@@ -105,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 0277b882b7..77a6d13a23 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell/html.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell/html.rb
@@ -76,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/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/vendor/tsort/.document b/lib/bundler/vendor/tsort/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/tsort/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/tsort/lib/tsort.rb b/lib/bundler/vendor/tsort/lib/tsort.rb
index cf8731f760..4a0e1a4e25 100644
--- a/lib/bundler/vendor/tsort/lib/tsort.rb
+++ b/lib/bundler/vendor/tsort/lib/tsort.rb
@@ -122,9 +122,6 @@
#
module Bundler::TSort
-
- VERSION = "0.2.0"
-
class Cyclic < StandardError
end
diff --git a/lib/bundler/vendor/uri/.document b/lib/bundler/vendor/uri/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/uri/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/uri/lib/uri/common.rb b/lib/bundler/vendor/uri/lib/uri/common.rb
index 89044da036..914a4c7581 100644
--- a/lib/bundler/vendor/uri/lib/uri/common.rb
+++ b/lib/bundler/vendor/uri/lib/uri/common.rb
@@ -19,8 +19,6 @@ module Bundler::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)
# Bundler::URI::Parser.new
DEFAULT_PARSER = Parser.new
@@ -70,32 +68,16 @@ module Bundler::URI
end
private_constant :Schemes
- # Registers the given +klass+ as the class to be instantiated
- # when parsing a \Bundler::URI with the given +scheme+:
#
- # Bundler::URI.register_scheme('MS_SEARCH', Bundler::URI::Generic) # => Bundler::URI::Generic
- # Bundler::URI.scheme_list['MS_SEARCH'] # => Bundler::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:
- #
- # Bundler::URI.scheme_list
- # # =>
- # {"MAILTO"=>Bundler::URI::MailTo,
- # "LDAPS"=>Bundler::URI::LDAPS,
- # "WS"=>Bundler::URI::WS,
- # "HTTP"=>Bundler::URI::HTTP,
- # "HTTPS"=>Bundler::URI::HTTPS,
- # "LDAP"=>Bundler::URI::LDAP,
- # "FILE"=>Bundler::URI::File,
- # "FTP"=>Bundler::URI::FTP}
- #
- # Related: Bundler::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)]
@@ -106,21 +88,9 @@ module Bundler::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>Bundler::URI.scheme_list[scheme.upcase]</tt>.
- # - The object is initialized by calling the class initializer
- # using +scheme+ and +arguments+.
- # See Bundler::URI::Generic.new.
- #
- # Examples:
#
- # values = ['john.doe', 'www.example.com', '123', nil, '/forum/questions/', nil, 'tag=networking&order=newest', 'top']
- # Bundler::URI.for('https', *values)
- # # => #<Bundler::URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # Bundler::URI.for('foo', *values, default: Bundler::URI::HTTP)
- # # => #<Bundler::URI::HTTP foo://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
+ # Construct a Bundler::URI instance, using the scheme to detect the appropriate class
+ # from +Bundler::URI.scheme_list+.
#
def self.for(scheme, *arguments, default: Generic)
const_name = scheme.to_s.upcase
@@ -151,49 +121,95 @@ module Bundler::URI
#
class BadURIError < Error; end
- # Returns a 9-element array representing the parts of the \Bundler::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 = Bundler::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
+ #
+ # Bundler::URI::split(uri)
+ #
+ # == Args
+ #
+ # +uri+::
+ # String with Bundler::URI.
+ #
+ # == Description
+ #
+ # Splits the string on following parts and returns array with result:
+ #
+ # * Scheme
+ # * Userinfo
+ # * Host
+ # * Port
+ # * Registry
+ # * Path
+ # * Opaque
+ # * Query
+ # * Fragment
+ #
+ # == Usage
+ #
+ # require 'bundler/vendor/uri/lib/uri'
+ #
+ # Bundler::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 \Bundler::URI object constructed from the given string +uri+:
#
- # Bundler::URI.parse('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<Bundler::URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # Bundler::URI.parse('http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<Bundler::URI::HTTP http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
+ # == Synopsis
+ #
+ # Bundler::URI::parse(uri_str)
+ #
+ # == Args
+ #
+ # +uri_str+::
+ # String with Bundler::URI.
+ #
+ # == Description
+ #
+ # Creates one of the Bundler::URI's subclasses instance from the string.
+ #
+ # == Raises
+ #
+ # Bundler::URI::InvalidURIError::
+ # Raised if Bundler::URI given is not a correct one.
#
- # It's recommended to first ::escape string +uri+
- # if it may contain invalid Bundler::URI characters.
+ # == Usage
+ #
+ # require 'bundler/vendor/uri/lib/uri'
+ #
+ # uri = Bundler::URI.parse("http://www.ruby-lang.org/")
+ # # => #<Bundler::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 Bundler::URI characters.
#
def self.parse(uri)
RFC3986_PARSER.parse(uri)
end
- # Merges the given Bundler::URI strings +str+
- # per {RFC 2396}[https://www.rfc-editor.org/rfc/rfc2396.html].
#
- # Each string in +str+ is converted to an
- # {RFC3986 Bundler::URI}[https://www.rfc-editor.org/rfc/rfc3986.html] before being merged.
+ # == Synopsis
+ #
+ # Bundler::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 'bundler/vendor/uri/lib/uri'
#
# Bundler::URI.join("http://example.com/","main.rbx")
# # => #<Bundler::URI::HTTP http://example.com/main.rbx>
@@ -238,7 +254,7 @@ module Bundler::URI
# Bundler::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 "Bundler::URI.extract is obsolete", uplevel: 1 if $VERBOSE
DEFAULT_PARSER.extract(str, schemes, &block)
end
@@ -275,7 +291,7 @@ module Bundler::URI
# p $&
# end
#
- def self.regexp(schemes = nil)# :nodoc:
+ def self.regexp(schemes = nil)
warn "Bundler::URI.regexp is obsolete", uplevel: 1 if $VERBOSE
DEFAULT_PARSER.make_regexp(schemes)
end
@@ -298,86 +314,40 @@ module Bundler::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.
#
- # Bundler::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:
- #
- # Bundler::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: Bundler::URI.encode_uri_component (encodes <tt>' '</tt> as <tt>'%20'</tt>).
+ # See Bundler::URI.decode_www_form_component, Bundler::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:
- #
- # Bundler::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.
#
- # Bundler::URI.decode_www_form_component('Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A')
- # # => "Here are some punctuation characters: ,;?:"
- #
- # Related: Bundler::URI.decode_uri_component (preserves <tt>'+'</tt>).
+ # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form.
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
_decode_uri_component(/\+|%\h\h/, str, enc)
end
- # Like Bundler::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 Bundler::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
@@ -402,104 +372,33 @@ module Bundler::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:
- #
- # Bundler::URI.encode_www_form([['foo', 0], ['bar', 1], ['baz', 2]])
- # # => "foo=0&bar=1&baz=2"
- # Bundler::URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The returned string is formed using method Bundler::URI.encode_www_form_component,
- # which converts certain characters:
- #
- # Bundler::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 = Bundler::URI.encode_www_form_component(ele[0], enc)
- # value = Bundler::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.
#
- # Bundler::URI.encode_www_form([%w[foo bar], %w[baz bat bah]])
- # # => "foo=bar&baz=bat"
- # Bundler::URI.encode_www_form([['foo', 0], ['bar', :baz, 'bat']])
- # # => "foo=0&bar=baz"
+ # This internally uses Bundler::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.)
#
- # Bundler::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
#
- # Bundler::URI.encode_www_form([['foo'], [:bar], [0]])
- # # => "foo&bar&0"
- #
- # - Otherwise the field is formed from +ele+:
- #
- # Bundler::URI.encode_www_form_component(ele)
- #
- # Example:
- #
- # Bundler::URI.encode_www_form(['foo', :bar, 0])
- # # => "foo&bar&0"
- #
- # The elements of an Array-like +enum+ may be mixture:
- #
- # Bundler::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 = Bundler::URI.encode_www_form_component(key, enc)
- # value = Bundler::URI.encode_www_form_component(ele, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # Bundler::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 = Bundler::URI.encode_www_form_component(key, enc)
- # value = Bundler::URI.encode_www_form_component(value, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # Bundler::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:
- #
- # Bundler::URI.encode_www_form({foo: [0, 1], bar: 2})
- # # => "foo=0&foo=1&bar=2"
+ # Bundler::URI.encode_www_form([["q", "ruby"], ["lang", "en"]])
+ # #=> "q=ruby&lang=en"
+ # Bundler::URI.encode_www_form("q" => "ruby", "lang" => "en")
+ # #=> "q=ruby&lang=en"
+ # Bundler::URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en")
+ # #=> "q=ruby&q=perl&lang=en"
+ # Bundler::URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]])
+ # #=> "q=ruby&q=perl&lang=en"
#
+ # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form.
def self.encode_www_form(enum, enc=nil)
enum.map do |k,v|
if v.nil?
@@ -520,39 +419,22 @@ module Bundler::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.
#
- # Bundler::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 Bundler::URI.decode_www_form_component:
- #
- # Bundler::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:
- #
- # Bundler::URI.decode_www_form('foo=0&&bar=1&&baz=2')
- # # => [["foo", "0"], ["", ""], ["bar", "1"], ["", ""], ["baz", "2"]]
- #
- # A different separator may be specified:
- #
- # Bundler::URI.decode_www_form('foo=0--bar=1--baz', separator: '--')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
+ # ary = Bundler::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 Bundler::URI.decode_www_form_component, Bundler::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 = []
@@ -831,15 +713,7 @@ end # module Bundler::URI
module Bundler
#
- # Returns a \Bundler::URI object derived from the given +uri+,
- # which may be a \Bundler::URI string or an existing \Bundler::URI object:
- #
- # # Returns a new Bundler::URI.
- # uri = Bundler::URI('http://github.com/ruby/ruby')
- # # => #<Bundler::URI::HTTP http://github.com/ruby/ruby>
- # # Returns the given Bundler::URI.
- # Bundler::URI(uri)
- # # => #<Bundler::URI::HTTP http://github.com/ruby/ruby>
+ # Returns +uri+ converted to an Bundler::URI object.
#
def URI(uri)
if uri.is_a?(Bundler::URI::Generic)
diff --git a/lib/bundler/vendor/uri/lib/uri/generic.rb b/lib/bundler/vendor/uri/lib/uri/generic.rb
index 762c425ac1..9ae6915826 100644
--- a/lib/bundler/vendor/uri/lib/uri/generic.rb
+++ b/lib/bundler/vendor/uri/lib/uri/generic.rb
@@ -1376,7 +1376,6 @@ module Bundler::URI
end
str
end
- alias to_str to_s
#
# Compares two URIs.
diff --git a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
index 09c22c9906..2f8d55353b 100644
--- a/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
+++ b/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb
@@ -497,8 +497,8 @@ module Bundler::URI
ret = {}
# for Bundler::URI::split
- ret[:ABS_URI] = Regexp.new('\A\s*+' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
- ret[:REL_URI] = Regexp.new('\A\s*+' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
+ ret[:ABS_URI] = Regexp.new('\A\s*' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
+ ret[:REL_URI] = Regexp.new('\A\s*' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
# for Bundler::URI::extract
ret[:URI_REF] = Regexp.new(pattern[:URI_REF])
diff --git a/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb b/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
index 4c9882f595..1307e8e474 100644
--- a/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
+++ b/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
@@ -1,73 +1,9 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
module Bundler::URI
class RFC3986_Parser # :nodoc:
# Bundler::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}
- (?<Bundler::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(?<Bundler::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 Bundler::URI
uri.ascii_only? or
raise InvalidURIError, "Bundler::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 Bundler::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 Bundler::URI(is not Bundler::URI?): #{uri.inspect}"
@@ -156,15 +92,15 @@ module Bundler::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],
- PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\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/bundler/vendor/uri/lib/uri/version.rb b/lib/bundler/vendor/uri/lib/uri/version.rb
index ac94e15221..02fa367735 100644
--- a/lib/bundler/vendor/uri/lib/uri/version.rb
+++ b/lib/bundler/vendor/uri/lib/uri/version.rb
@@ -1,6 +1,6 @@
module Bundler::URI
# :stopdoc:
- VERSION_CODE = '001301'.freeze
+ VERSION_CODE = '001200'.freeze
VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
# :startdoc:
end
diff --git a/lib/bundler/vendored_net_http.rb b/lib/bundler/vendored_net_http.rb
deleted file mode 100644
index 8ff2ccd1fe..0000000000
--- a/lib/bundler/vendored_net_http.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-# This defined? guard can be removed once RubyGems 3.4 support is dropped.
-#
-# Bundler specs load this code from `spec/support/vendored_net_http.rb` to avoid
-# activating the Bundler gem too early. Without this guard, we get redefinition
-# warnings once Bundler is actually activated and
-# `lib/bundler/vendored_net_http.rb` is required. This is not an issue in
-# RubyGems versions including `rubygems/vendored_net_http` since `require` takes
-# care of avoiding the double load.
-#
-unless defined?(Gem::Net)
- begin
- require "rubygems/vendored_net_http"
- rescue LoadError
- begin
- require "rubygems/net/http"
- rescue LoadError
- require "net/http"
- Gem::Net = Net
- end
- end
-end
diff --git a/lib/bundler/vendored_persistent.rb b/lib/bundler/vendored_persistent.rb
index ab985c267f..e29f27cdfd 100644
--- a/lib/bundler/vendored_persistent.rb
+++ b/lib/bundler/vendored_persistent.rb
@@ -9,3 +9,7 @@ module Bundler
end
end
require_relative "vendor/net-http-persistent/lib/net/http/persistent"
+
+module Bundler
+ PersistentHTTP = Persistent::Net::HTTP::Persistent
+end
diff --git a/lib/bundler/vendored_securerandom.rb b/lib/bundler/vendored_securerandom.rb
deleted file mode 100644
index 6c15f4a2b2..0000000000
--- a/lib/bundler/vendored_securerandom.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-# Use RubyGems vendored copy when available. Otherwise fallback to Bundler
-# vendored copy. The vendored copy in Bundler can be removed once support for
-# RubyGems 3.5.18 is dropped.
-
-begin
- require "rubygems/vendored_securerandom"
-rescue LoadError
- module Bundler::Random; end
- require_relative "vendor/securerandom/lib/securerandom"
- Gem::SecureRandom = Bundler::SecureRandom
- Gem::Random = Bundler::Random
-end
diff --git a/lib/bundler/vendored_timeout.rb b/lib/bundler/vendored_timeout.rb
deleted file mode 100644
index 9b2507c0cc..0000000000
--- a/lib/bundler/vendored_timeout.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-begin
- require "rubygems/vendored_timeout"
-rescue LoadError
- begin
- require "rubygems/timeout"
- rescue LoadError
- require "timeout"
- Gem::Timeout = Timeout
- end
-end
diff --git a/lib/bundler/vendored_uri.rb b/lib/bundler/vendored_uri.rb
index 2efddc65f9..905e8158e8 100644
--- a/lib/bundler/vendored_uri.rb
+++ b/lib/bundler/vendored_uri.rb
@@ -1,21 +1,4 @@
# frozen_string_literal: true
module Bundler; end
-
-# Use RubyGems vendored copy when available. Otherwise fallback to Bundler
-# vendored copy. The vendored copy in Bundler can be removed once support for
-# RubyGems 3.5 is dropped.
-
-begin
- require "rubygems/vendor/uri/lib/uri"
-rescue LoadError
- require_relative "vendor/uri/lib/uri"
- Gem::URI = Bundler::URI
-
- module Gem
- def URI(uri) # rubocop:disable Naming/MethodName
- Bundler::URI(uri)
- end
- module_function :URI
- end
-end
+require_relative "vendor/uri/lib/uri"
diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb
index b8bfd4fc18..d3bd162e48 100644
--- a/lib/bundler/version.rb
+++ b/lib/bundler/version.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: false
module Bundler
- VERSION = "2.5.22".freeze
+ VERSION = "2.4.6".freeze
def self.bundler_major_version
@bundler_major_version ||= VERSION.split(".").first.to_i
diff --git a/lib/bundler/vlad.rb b/lib/bundler/vlad.rb
index 6179d0e4eb..538e8c3e74 100644
--- a/lib/bundler/vlad.rb
+++ b/lib/bundler/vlad.rb
@@ -13,5 +13,5 @@ require_relative "deployment"
include Rake::DSL if defined? Rake::DSL
namespace :vlad do
- Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, roles: :app)
+ Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, :roles => :app)
end
diff --git a/lib/bundler/yaml_serializer.rb b/lib/bundler/yaml_serializer.rb
index ab1eb6dbcf..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
@@ -36,31 +32,30 @@ module Bundler
(.*) # value
\1 # matching closing quote
$
- /xo
+ /xo.freeze
HASH_REGEX = /
^
([ ]*) # indentations
- ([^#]+) # key excludes comment char '#'
+ (.+) # key
(?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value)
[ ]?
(['"]?) # optional opening quote
(.*) # value
\3 # matching closing quote
$
- /xo
+ /xo.freeze
def load(str)
res = {}
stack = [res]
last_hash = nil
last_empty_key = nil
- str.split(/\r?\n/) do |line|
+ str.split(/\r?\n/).each do |line|
if match = HASH_REGEX.match(line)
indent, key, quote, val = match.captures
- val = strip_comment(val)
-
- 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
@@ -68,13 +63,10 @@ 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)
_, val = match.captures
- val = strip_comment(val)
-
last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array)
last_hash[last_empty_key].push(val)
@@ -83,16 +75,15 @@ module Bundler
res
end
- def strip_comment(val)
- if val.include?("#") && !val.start_with?("#")
- val.split("#", 2).first.strip
- else
- val
- end
+ # for settings' keys
+ 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
+ private :dump_hash, :convert_to_backward_compatible_key
end
end
end
diff --git a/lib/cgi.rb b/lib/cgi.rb
index 69c3c4fd24..4cd6b3bd8e 100644
--- a/lib/cgi.rb
+++ b/lib/cgi.rb
@@ -288,7 +288,7 @@
#
class CGI
- VERSION = "0.4.2"
+ VERSION = "0.3.6"
end
require 'cgi/core'
diff --git a/lib/cgi/cgi.gemspec b/lib/cgi/cgi.gemspec
index 5ef00d591d..381c55a5ca 100644
--- a/lib/cgi/cgi.gemspec
+++ b/lib/cgi/cgi.gemspec
@@ -25,8 +25,7 @@ Gem::Specification.new do |spec|
spec.executables = []
spec.files = [
- "COPYING",
- "BSDL",
+ "LICENSE.txt",
"README.md",
*Dir["lib{.rb,/**/*.rb}", "bin/*"] ]
diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb
index 1c4ef6a600..9498e2f9fa 100644
--- a/lib/cgi/cookie.rb
+++ b/lib/cgi/cookie.rb
@@ -190,10 +190,9 @@ class CGI
values ||= ""
values = values.split('&').collect{|v| CGI.unescape(v,@@accept_charset) }
if cookies.has_key?(name)
- cookies[name].concat(values)
- else
- cookies[name] = Cookie.new(name, *values)
+ values = cookies[name].value + 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/session/pstore.rb b/lib/cgi/session/pstore.rb
index 6e3d10f075..45d0d8ae2c 100644
--- a/lib/cgi/session/pstore.rb
+++ b/lib/cgi/session/pstore.rb
@@ -11,10 +11,7 @@
# cgi/session.rb for more details on session storage managers.
require_relative '../session'
-begin
- require 'pstore'
-rescue LoadError
-end
+require 'pstore'
class CGI
class Session
@@ -85,7 +82,7 @@ class CGI
File::unlink path
end
- end if defined?(::PStore)
+ end
end
end
# :enddoc:
diff --git a/lib/cgi/util.rb b/lib/cgi/util.rb
index 5f12eae130..5a5c77ac97 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("|")})\b[^<>]*+>?/im) do
+ string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) 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("|")})\b(?>[^&]+|&(?![gl]t;)\w+;)*(?:&gt;)?/im) do
+ string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/i) 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/error_highlight/version.rb b/lib/error_highlight/version.rb
index 506d37fbc1..5afe5f06d6 100644
--- a/lib/error_highlight/version.rb
+++ b/lib/error_highlight/version.rb
@@ -1,3 +1,3 @@
module ErrorHighlight
- VERSION = "0.6.0"
+ VERSION = "0.5.1"
end
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 03e1c18baa..7a5cf94830 100644
--- a/lib/ipaddr.rb
+++ b/lib/ipaddr.rb
@@ -40,7 +40,7 @@ require 'socket'
# p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
class IPAddr
- VERSION = "1.2.6"
+ VERSION = "1.2.5"
# 32 bit mask for IPv4
IN4MASK = 0xffffffff
@@ -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 b3435c257e..2db99bcd43 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -1,895 +1,412 @@
-# frozen_string_literal: true
-
-# :markup: markdown
+# 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"
require_relative "irb/init"
require_relative "irb/context"
-require_relative "irb/default_commands"
+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"
-require_relative "irb/pager"
-# ## IRB
+# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
+# expressions read from the standard input.
#
-# Module IRB ("Interactive Ruby") provides a shell-like interface that supports
-# user interaction with the Ruby interpreter.
+# The +irb+ command from your shell will start the interpreter.
#
-# It operates as a *read-eval-print loop*
-# ([REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop))
-# that:
+# == Usage
#
-# * ***Reads*** each character as you type. You can modify the IRB context to
-# change the way input works. See [Input](rdoc-ref:IRB@Input).
-# * ***Evaluates*** the code each time it has read a syntactically complete
-# passage.
-# * ***Prints*** after evaluating. You can modify the IRB context to change
-# the way output works. See [Output](rdoc-ref:IRB@Output).
+# Use of irb is easy if you know Ruby.
#
-#
-# Example:
+# When executing irb, prompts are displayed as follows. Then, enter the Ruby
+# expression. An input is executed when it is syntactically complete.
#
# $ irb
-# irb(main):001> File.basename(Dir.pwd)
-# => "irb"
-# irb(main):002> Dir.entries('.').size
-# => 25
-# irb(main):003* Dir.entries('.').select do |entry|
-# irb(main):004* entry.start_with?('R')
-# irb(main):005> end
-# => ["README.md", "Rakefile"]
-#
-# The typed input may also include [\IRB-specific
-# commands](rdoc-ref:IRB@IRB-Specific+Commands).
-#
-# As seen above, you can start IRB by using the shell command `irb`.
-#
-# You can stop an IRB session by typing command `exit`:
-#
-# irb(main):006> exit
-# $
-#
-# At that point, IRB calls any hooks found in array `IRB.conf[:AT_EXIT]`, then
-# exits.
-#
-# ## Startup
-#
-# At startup, IRB:
-#
-# 1. Interprets (as Ruby code) the content of the [configuration
-# file](rdoc-ref:IRB@Configuration+File) (if given).
-# 2. Constructs the initial session context from [hash
-# IRB.conf](rdoc-ref:IRB@Hash+IRB.conf) and from default values; the hash
-# content may have been affected by [command-line
-# options](rdoc-ref:IB@Command-Line+Options), and by direct assignments in
-# the configuration file.
-# 3. Assigns the context to variable `conf`.
-# 4. Assigns command-line arguments to variable `ARGV`.
-# 5. Prints the [prompt](rdoc-ref:IRB@Prompt+and+Return+Formats).
-# 6. Puts the content of the [initialization
-# script](rdoc-ref:IRB@Initialization+Script) onto the IRB shell, just as if
-# it were user-typed commands.
-#
-#
-# ### The Command Line
-#
-# On the command line, all options precede all arguments; the first item that is
-# not recognized as an option is treated as an argument, as are all items that
-# follow.
-#
-# #### Command-Line Options
-#
-# Many command-line options affect entries in hash `IRB.conf`, which in turn
-# affect the initial configuration of the IRB session.
-#
-# Details of the options are described in the relevant subsections below.
-#
-# A cursory list of the IRB command-line options may be seen in the [help
-# message](https://raw.githubusercontent.com/ruby/irb/master/lib/irb/lc/help-message),
-# which is also displayed if you use command-line option `--help`.
-#
-# If you are interested in a specific option, consult the
-# [index](rdoc-ref:doc/irb/indexes.md@Index+of+Command-Line+Options).
-#
-# #### Command-Line Arguments
-#
-# Command-line arguments are passed to IRB in array `ARGV`:
-#
-# $ irb --noscript Foo Bar Baz
-# irb(main):001> ARGV
-# => ["Foo", "Bar", "Baz"]
-# irb(main):002> exit
-# $
-#
-# Command-line option `--` causes everything that follows to be treated as
-# arguments, even those that look like options:
-#
-# $ irb --noscript -- --noscript -- Foo Bar Baz
-# irb(main):001> ARGV
-# => ["--noscript", "--", "Foo", "Bar", "Baz"]
-# irb(main):002> exit
-# $
-#
-# ### Configuration File
-#
-# You can initialize IRB via a *configuration file*.
-#
-# If command-line option `-f` is given, no configuration file is looked for.
-#
-# Otherwise, IRB reads and interprets a configuration file if one is available.
-#
-# The configuration file can contain any Ruby code, and can usefully include
-# user code that:
-#
-# * Can then be debugged in IRB.
-# * Configures IRB itself.
-# * Requires or loads files.
-#
-#
-# The path to the configuration file is the first found among:
-#
-# * The value of variable `$IRBRC`, if defined.
-# * The value of variable `$XDG_CONFIG_HOME/irb/irbrc`, if defined.
-# * File `$HOME/.irbrc`, if it exists.
-# * File `$HOME/.config/irb/irbrc`, if it exists.
-# * File `.irbrc` in the current directory, if it exists.
-# * File `irb.rc` in the current directory, if it exists.
-# * File `_irbrc` in the current directory, if it exists.
-# * File `$irbrc` in the current directory, if it exists.
-#
-#
-# If the search fails, there is no configuration file.
-#
-# If the search succeeds, the configuration file is read as Ruby code, and so
-# can contain any Ruby programming you like.
-#
-# Method `conf.rc?` returns `true` if a configuration file was read, `false`
-# otherwise. Hash entry `IRB.conf[:RC]` also contains that value.
-#
-# ### Hash `IRB.conf`
-#
-# The initial entries in hash `IRB.conf` are determined by:
-#
-# * Default values.
-# * Command-line options, which may override defaults.
-# * Direct assignments in the configuration file.
-#
-#
-# You can see the hash by typing `IRB.conf`.
-#
-# Details of the entries' meanings are described in the relevant subsections
-# below.
-#
-# If you are interested in a specific entry, consult the
-# [index](rdoc-ref:doc/irb/indexes.md@Index+of+IRB.conf+Entries).
-#
-# ### Notes on Initialization Precedence
-#
-# * Any conflict between an entry in hash `IRB.conf` and a command-line option
-# is resolved in favor of the hash entry.
-# * Hash `IRB.conf` affects the context only once, when the configuration file
-# is interpreted; any subsequent changes to it do not affect the context and
-# are therefore essentially meaningless.
-#
-#
-# ### Initialization Script
-#
-# By default, the first command-line argument (after any options) is the path to
-# a Ruby initialization script.
-#
-# IRB reads the initialization script and puts its content onto the IRB shell,
-# just as if it were user-typed commands.
-#
-# Command-line option `--noscript` causes the first command-line argument to be
-# treated as an ordinary argument (instead of an initialization script);
-# `--script` is the default.
-#
-# ## Input
-#
-# This section describes the features that allow you to change the way IRB input
-# works; see also [Input and Output](rdoc-ref:IRB@Input+and+Output).
-#
-# ### Input Command History
-#
-# By default, IRB stores a history of up to 1000 input commands in a file named
-# `.irb_history`. The history file will be in the same directory as the
-# [configuration file](rdoc-ref:IRB@Configuration+File) if one is found, or in
-# `~/` otherwise.
-#
-# A new IRB session creates the history file if it does not exist, and appends
-# to the file if it does exist.
-#
-# You can change the filepath by adding to your configuration file:
-# `IRB.conf[:HISTORY_FILE] = *filepath*`, where *filepath* is a string filepath.
-#
-# During the session, method `conf.history_file` returns the filepath, and
-# method `conf.history_file = *new_filepath*` copies the history to the file at
-# *new_filepath*, which becomes the history file for the session.
-#
-# You can change the number of commands saved by adding to your configuration
-# file: `IRB.conf[:SAVE_HISTORY] = *n*`, wheHISTORY_FILEre *n* is one of:
-#
-# * Positive integer: the number of commands to be saved,
-# * Zero: all commands are to be saved.
-# * `nil`: no commands are to be saved,.
-#
-#
-# During the session, you can use methods `conf.save_history` or
-# `conf.save_history=` to retrieve or change the count.
-#
-# ### Command Aliases
-#
-# By default, IRB defines several command aliases:
-#
-# irb(main):001> conf.command_aliases
-# => {:"$"=>:show_source, :"@"=>:whereami}
-#
-# You can change the initial aliases in the configuration file with:
-#
-# IRB.conf[:COMMAND_ALIASES] = {foo: :show_source, bar: :whereami}
-#
-# You can replace the current aliases at any time with configuration method
-# `conf.command_aliases=`; Because `conf.command_aliases` is a hash, you can
-# modify it.
-#
-# ### End-of-File
-#
-# By default, `IRB.conf[:IGNORE_EOF]` is `false`, which means that typing the
-# end-of-file character `Ctrl-D` causes the session to exit.
-#
-# You can reverse that behavior by adding `IRB.conf[:IGNORE_EOF] = true` to the
-# configuration file.
-#
-# During the session, method `conf.ignore_eof?` returns the setting, and method
-# `conf.ignore_eof = *boolean*` sets it.
-#
-# ### SIGINT
-#
-# By default, `IRB.conf[:IGNORE_SIGINT]` is `true`, which means that typing the
-# interrupt character `Ctrl-C` causes the session to exit.
-#
-# You can reverse that behavior by adding `IRB.conf[:IGNORE_SIGING] = false` to
-# the configuration file.
-#
-# During the session, method `conf.ignore_siging?` returns the setting, and
-# method `conf.ignore_sigint = *boolean*` sets it.
-#
-# ### Automatic Completion
-#
-# By default, IRB enables [automatic
-# completion](https://en.wikipedia.org/wiki/Autocomplete#In_command-line_interpr
-# eters):
-#
-# You can disable it by either of these:
-#
-# * Adding `IRB.conf[:USE_AUTOCOMPLETE] = false` to the configuration file.
-# * Giving command-line option `--noautocomplete` (`--autocomplete` is the
-# default).
-#
-#
-# Method `conf.use_autocomplete?` returns `true` if automatic completion is
-# enabled, `false` otherwise.
-#
-# The setting may not be changed during the session.
-#
-# ### Automatic Indentation
-#
-# By default, IRB automatically indents lines of code to show structure (e.g.,
-# it indent the contents of a block).
-#
-# The current setting is returned by the configuration method
-# `conf.auto_indent_mode`.
-#
-# The default initial setting is `true`:
-#
-# irb(main):001> conf.auto_indent_mode
-# => true
-# irb(main):002* Dir.entries('.').select do |entry|
-# irb(main):003* entry.start_with?('R')
-# irb(main):004> end
-# => ["README.md", "Rakefile"]
-#
-# You can change the initial setting in the configuration file with:
+# irb(main):001:0> 1+2
+# #=> 3
+# irb(main):002:0> class Foo
+# irb(main):003:1> def foo
+# irb(main):004:2> print 1
+# irb(main):005:2> end
+# irb(main):006:1> end
+# #=> nil
+#
+# The singleline editor module or multiline editor module can be used with irb.
+# Use of multiline editor is default if it's installed.
+#
+# == Command line options
+#
+# :include: ./irb/lc/help-message
+#
+# == Commands
+#
+# The following commands are available on IRB.
+#
+# * cwws
+# * Show the current workspace.
+# * cb, cws, chws
+# * Change the current workspace to an object.
+# * bindings, workspaces
+# * Show workspaces.
+# * pushb, pushws
+# * Push an object to the workspace stack.
+# * popb, popws
+# * Pop a workspace from the workspace stack.
+# * load
+# * Load a Ruby file.
+# * require
+# * Require a Ruby file.
+# * source
+# * Loads a given file in the current session.
+# * irb
+# * Start a child IRB.
+# * jobs
+# * List of current sessions.
+# * fg
+# * Switches to the session of the given number.
+# * kill
+# * Kills the session with the given number.
+# * help
+# * Enter the mode to look up RI documents.
+# * irb_info
+# * Show information about IRB.
+# * ls
+# * Show methods, constants, and variables.
+# -g [query] or -G [query] allows you to filter out the output.
+# * measure
+# * measure enables the mode to measure processing time. measure :off disables it.
+# * $, show_source
+# * Show the source code of a given method or constant.
+# * @, whereami
+# * Show the source code around binding.irb again.
+# * debug
+# * Start the debugger of debug.gem.
+# * break, delete, next, step, continue, finish, backtrace, info, catch
+# * Start the debugger of debug.gem and run the command on it.
+#
+# == Configuration
+#
+# IRB reads a personal initialization file when it's invoked.
+# IRB searches a file in the following order and loads the first one found.
+#
+# * <tt>$IRBRC</tt> (if <tt>$IRBRC</tt> is set)
+# * <tt>$XDG_CONFIG_HOME/irb/irbrc</tt> (if <tt>$XDG_CONFIG_HOME</tt> is set)
+# * <tt>~/.irbrc</tt>
+# * +.config/irb/irbrc+
+# * +.irbrc+
+# * +irb.rc+
+# * +_irbrc+
+# * <code>$irbrc</code>
+#
+# The following are alternatives to the command line options. To use them type
+# as follows in an +irb+ session:
+#
+# IRB.conf[:IRB_NAME]="irb"
+# IRB.conf[:INSPECT_MODE]=nil
+# IRB.conf[:IRB_RC] = nil
+# IRB.conf[:BACK_TRACE_LIMIT]=16
+# IRB.conf[:USE_LOADER] = false
+# IRB.conf[:USE_MULTILINE] = nil
+# IRB.conf[:USE_SINGLELINE] = nil
+# IRB.conf[:USE_COLORIZE] = true
+# IRB.conf[:USE_TRACER] = false
+# IRB.conf[:USE_AUTOCOMPLETE] = true
+# IRB.conf[:IGNORE_SIGINT] = true
+# IRB.conf[:IGNORE_EOF] = false
+# IRB.conf[:PROMPT_MODE] = :DEFAULT
+# IRB.conf[:PROMPT] = {...}
+#
+# === Auto indentation
+#
+# To disable auto-indent mode in irb, add the following to your +.irbrc+:
#
# IRB.conf[:AUTO_INDENT] = false
#
-# Note that the *current* setting *may not* be changed in the IRB session.
-#
-# ### Input Method
-#
-# The IRB input method determines how command input is to be read; by default,
-# the input method for a session is IRB::RelineInputMethod. Unless the
-# value of the TERM environment variable is 'dumb', in which case the
-# most simplistic input method is used.
-#
-# You can set the input method by:
-#
-# * Adding to the configuration file:
-#
-# * `IRB.conf[:USE_SINGLELINE] = true` or `IRB.conf[:USE_MULTILINE]=
-# false` sets the input method to IRB::ReadlineInputMethod.
-# * `IRB.conf[:USE_SINGLELINE] = false` or `IRB.conf[:USE_MULTILINE] =
-# true` sets the input method to IRB::RelineInputMethod.
-#
-#
-# * Giving command-line options:
-#
-# * `--singleline` or `--nomultiline` sets the input method to
-# IRB::ReadlineInputMethod.
-# * `--nosingleline` or `--multiline` sets the input method to
-# IRB::RelineInputMethod.
-# * `--nosingleline` together with `--nomultiline` sets the
-# input to IRB::StdioInputMethod.
-#
-#
-# Method `conf.use_multiline?` and its synonym `conf.use_reline` return:
-#
-# * `true` if option `--multiline` was given.
-# * `false` if option `--nomultiline` was given.
-# * `nil` if neither was given.
-#
-#
-# Method `conf.use_singleline?` and its synonym `conf.use_readline` return:
-#
-# * `true` if option `--singleline` was given.
-# * `false` if option `--nosingleline` was given.
-# * `nil` if neither was given.
-#
-#
-# ## Output
-#
-# This section describes the features that allow you to change the way IRB
-# output works; see also [Input and Output](rdoc-ref:IRB@Input+and+Output).
-#
-# ### Return-Value Printing (Echoing)
-#
-# By default, IRB prints (echoes) the values returned by all input commands.
-#
-# You can change the initial behavior and suppress all echoing by:
-#
-# * Adding to the configuration file: `IRB.conf[:ECHO] = false`. (The default
-# value for this entry is `nil`, which means the same as `true`.)
-# * Giving command-line option `--noecho`. (The default is `--echo`.)
-#
-#
-# During the session, you can change the current setting with configuration
-# method `conf.echo=` (set to `true` or `false`).
-#
-# As stated above, by default IRB prints the values returned by all input
-# commands; but IRB offers special treatment for values returned by assignment
-# statements, which may be:
-#
-# * Printed with truncation (to fit on a single line of output), which is the
-# default; an ellipsis (`...` is suffixed, to indicate the truncation):
-#
-# irb(main):001> x = 'abc' * 100
-#
-#
-# > "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc...
-#
-# * Printed in full (regardless of the length).
-# * Suppressed (not printed at all)
-#
+# === Autocompletion
#
-# You can change the initial behavior by:
+# To disable autocompletion for irb, add the following to your +.irbrc+:
#
-# * Adding to the configuration file: `IRB.conf[:ECHO_ON_ASSIGNMENT] = false`.
-# (The default value for this entry is `niL`, which means the same as
-# `:truncate`.)
-# * Giving command-line option `--noecho-on-assignment` or
-# `--echo-on-assignment`. (The default is `--truncate-echo-on-assignment`.)
+# IRB.conf[:USE_AUTOCOMPLETE] = false
#
+# === History
#
-# During the session, you can change the current setting with configuration
-# method `conf.echo_on_assignment=` (set to `true`, `false`, or `:truncate`).
+# By default, irb will store the last 1000 commands you used in
+# <code>IRB.conf[:HISTORY_FILE]</code> (<code>~/.irb_history</code> by default).
#
-# By default, IRB formats returned values by calling method `inspect`.
+# If you want to disable history, add the following to your +.irbrc+:
#
-# You can change the initial behavior by:
+# IRB.conf[:SAVE_HISTORY] = nil
#
-# * Adding to the configuration file: `IRB.conf[:INSPECT_MODE] = false`. (The
-# default value for this entry is `true`.)
-# * Giving command-line option `--noinspect`. (The default is `--inspect`.)
+# See IRB::Context#save_history= for more information.
#
+# The history of _results_ of commands evaluated is not stored by default,
+# but can be turned on to be stored with this +.irbrc+ setting:
#
-# During the session, you can change the setting using method
-# `conf.inspect_mode=`.
+# IRB.conf[:EVAL_HISTORY] = <number>
#
-# ### Multiline Output
+# See IRB::Context#eval_history= and History class. The history of command
+# results is not permanently saved in any file.
#
-# By default, IRB prefixes a newline to a multiline response.
+# == Customizing the IRB Prompt
#
-# You can change the initial default value by adding to the configuration file:
+# In order to customize the prompt, you can change the following Hash:
#
-# IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] = false
+# IRB.conf[:PROMPT]
#
-# During a session, you can retrieve or set the value using methods
-# `conf.newline_before_multiline_output?` and
-# `conf.newline_before_multiline_output=`.
+# This example can be used in your +.irbrc+
#
-# Examples:
-#
-# irb(main):001> conf.inspect_mode = false
-# => false
-# irb(main):002> "foo\nbar"
-# =>
-# foo
-# bar
-# irb(main):003> conf.newline_before_multiline_output = false
-# => false
-# irb(main):004> "foo\nbar"
-# => foo
-# bar
-#
-# ### Evaluation History
-#
-# By default, IRB saves no history of evaluations (returned values), and the
-# related methods `conf.eval_history`, `_`, and `__` are undefined.
-#
-# You can turn on that history, and set the maximum number of evaluations to be
-# stored:
-#
-# * In the configuration file: add `IRB.conf[:EVAL_HISTORY] = *n*`. (Examples
-# below assume that we've added `IRB.conf[:EVAL_HISTORY] = 5`.)
-# * In the session (at any time): `conf.eval_history = *n*`.
-#
-#
-# If `n` is zero, all evaluation history is stored.
-#
-# Doing either of the above:
-#
-# * Sets the maximum size of the evaluation history; defines method
-# `conf.eval_history`, which returns the maximum size `n` of the evaluation
-# history:
-#
-# irb(main):001> conf.eval_history = 5
-# => 5
-# irb(main):002> conf.eval_history
-# => 5
-#
-# * Defines variable `_`, which contains the most recent evaluation, or `nil`
-# if none; same as method `conf.last_value`:
-#
-# irb(main):003> _
-# => 5
-# irb(main):004> :foo
-# => :foo
-# irb(main):005> :bar
-# => :bar
-# irb(main):006> _
-# => :bar
-# irb(main):007> _
-# => :bar
-#
-# * Defines variable `__`:
-#
-# * `__` unadorned: contains all evaluation history:
-#
-# irb(main):008> :foo
-# => :foo
-# irb(main):009> :bar
-# => :bar
-# irb(main):010> :baz
-# => :baz
-# irb(main):011> :bat
-# => :bat
-# irb(main):012> :bam
-# => :bam
-# irb(main):013> __
-# =>
-# 9 :bar
-# 10 :baz
-# 11 :bat
-# 12 :bam
-# irb(main):014> __
-# =>
-# 10 :baz
-# 11 :bat
-# 12 :bam
-# 13 ...self-history...
-#
-# Note that when the evaluation is multiline, it is displayed
-# differently.
-#
-# * `__[`*m*`]`:
-#
-# * Positive *m*: contains the evaluation for the given line number,
-# or `nil` if that line number is not in the evaluation history:
-#
-# irb(main):015> __[12]
-# => :bam
-# irb(main):016> __[1]
-# => nil
-#
-# * Negative *m*: contains the `mth`-from-end evaluation, or `nil` if
-# that evaluation is not in the evaluation history:
-#
-# irb(main):017> __[-3]
-# => :bam
-# irb(main):018> __[-13]
-# => nil
-#
-# * Zero *m*: contains `nil`:
-#
-# irb(main):019> __[0]
-# => nil
-#
-#
-#
-#
-# ### Prompt and Return Formats
-#
-# By default, IRB uses the prompt and return value formats defined in its
-# `:DEFAULT` prompt mode.
-#
-# #### The Default Prompt and Return Format
-#
-# The default prompt and return values look like this:
-#
-# irb(main):001> 1 + 1
-# => 2
-# irb(main):002> 2 + 2
-# => 4
-#
-# The prompt includes:
-#
-# * The name of the running program (`irb`); see [IRB
-# Name](rdoc-ref:IRB@IRB+Name).
-# * The name of the current session (`main`); See [IRB
-# Sessions](rdoc-ref:IRB@IRB+Sessions).
-# * A 3-digit line number (1-based).
-#
-#
-# The default prompt actually defines three formats:
-#
-# * One for most situations (as above):
-#
-# irb(main):003> Dir
-# => Dir
-#
-# * One for when the typed command is a statement continuation (adds trailing
-# asterisk):
-#
-# irb(main):004* Dir.
-#
-# * One for when the typed command is a string continuation (adds trailing
-# single-quote):
-#
-# irb(main):005' Dir.entries('.
-#
-#
-# You can see the prompt change as you type the characters in the following:
-#
-# irb(main):001* Dir.entries('.').select do |entry|
-# irb(main):002* entry.start_with?('R')
-# irb(main):003> end
-# => ["README.md", "Rakefile"]
-#
-# #### Pre-Defined Prompts
-#
-# IRB has several pre-defined prompts, stored in hash `IRB.conf[:PROMPT]`:
-#
-# irb(main):001> IRB.conf[:PROMPT].keys
-# => [:NULL, :DEFAULT, :CLASSIC, :SIMPLE, :INF_RUBY, :XMP]
-#
-# To see the full data for these, type `IRB.conf[:PROMPT]`.
-#
-# Most of these prompt definitions include specifiers that represent values like
-# the IRB name, session name, and line number; see [Prompt
-# Specifiers](rdoc-ref:IRB@Prompt+Specifiers).
-#
-# You can change the initial prompt and return format by:
-#
-# * Adding to the configuration file: `IRB.conf[:PROMPT] = *mode*` where
-# *mode* is the symbol name of a prompt mode.
-# * Giving a command-line option:
-#
-# * `--prompt *mode*`: sets the prompt mode to *mode*. where *mode* is the
-# symbol name of a prompt mode.
-# * `--simple-prompt` or `--sample-book-mode`: sets the prompt mode to
-# `:SIMPLE`.
-# * `--inf-ruby-mode`: sets the prompt mode to `:INF_RUBY` and suppresses
-# both `--multiline` and `--singleline`.
-# * `--noprompt`: suppresses prompting; does not affect echoing.
-#
-#
-#
-# You can retrieve or set the current prompt mode with methods
-#
-# `conf.prompt_mode` and `conf.prompt_mode=`.
-#
-# If you're interested in prompts and return formats other than the defaults,
-# you might experiment by trying some of the others.
-#
-# #### Custom Prompts
-#
-# You can also define custom prompts and return formats, which may be done
-# either in an IRB session or in the configuration file.
-#
-# A prompt in IRB actually defines three prompts, as seen above. For simple
-# custom data, we'll make all three the same:
-#
-# irb(main):001* IRB.conf[:PROMPT][:MY_PROMPT] = {
-# irb(main):002* PROMPT_I: ': ',
-# irb(main):003* PROMPT_C: ': ',
-# irb(main):004* PROMPT_S: ': ',
-# irb(main):005* RETURN: '=> '
-# irb(main):006> }
-# => {:PROMPT_I=>": ", :PROMPT_C=>": ", :PROMPT_S=>": ", :RETURN=>"=> "}
-#
-# If you define the custom prompt in the configuration file, you can also make
-# it the current prompt by adding:
+# IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode
+# :AUTO_INDENT => false, # disables auto-indent mode
+# :PROMPT_I => ">> ", # simple prompt
+# :PROMPT_S => nil, # prompt for continuated strings
+# :PROMPT_C => nil, # prompt for continuated statement
+# :RETURN => " ==>%s\n" # format to return value
+# }
#
# IRB.conf[:PROMPT_MODE] = :MY_PROMPT
#
-# Regardless of where it's defined, you can make it the current prompt in a
-# session:
-#
-# conf.prompt_mode = :MY_PROMPT
-#
-# You can view or modify the current prompt data with various configuration
-# methods:
-#
-# * `conf.prompt_mode`, `conf.prompt_mode=`.
-# * `conf.prompt_c`, `conf.c=`.
-# * `conf.prompt_i`, `conf.i=`.
-# * `conf.prompt_s`, `conf.s=`.
-# * `conf.return_format`, `return_format=`.
-#
-#
-# #### Prompt Specifiers
-#
-# A prompt's definition can include specifiers for which certain values are
-# substituted:
-#
-# * `%N`: the name of the running program.
-# * `%m`: the value of `self.to_s`.
-# * `%M`: the value of `self.inspect`.
-# * `%l`: an indication of the type of string; one of `"`, `'`, `/`, `]`.
-# * `%NNi`: Indentation level. NN is a 2-digit number that specifies the number
-# of digits of the indentation level (03 will result in 001).
-# * `%NNn`: Line number. NN is a 2-digit number that specifies the number
-# of digits of the line number (03 will result in 001).
-# * `%%`: Literal `%`.
-#
-#
-# ### Verbosity
-#
-# By default, IRB verbosity is disabled, which means that output is smaller
-# rather than larger.
-#
-# You can enable verbosity by:
-#
-# * Adding to the configuration file: `IRB.conf[:VERBOSE] = true` (the default
-# is `nil`).
-# * Giving command-line options `--verbose` (the default is `--noverbose`).
-#
-#
-# During a session, you can retrieve or set verbosity with methods
-# `conf.verbose` and `conf.verbose=`.
-#
-# ### Help
-#
-# Command-line option `--version` causes IRB to print its help text and exit.
-#
-# ### Version
-#
-# Command-line option `--version` causes IRB to print its version text and exit.
-#
-# ## Input and Output
-#
-# ### Color Highlighting
-#
-# By default, IRB color highlighting is enabled, and is used for both:
-#
-# * Input: As you type, IRB reads the typed characters and highlights elements
-# that it recognizes; it also highlights errors such as mismatched
-# parentheses.
-# * Output: IRB highlights syntactical elements.
-#
-#
-# You can disable color highlighting by:
-#
-# * Adding to the configuration file: `IRB.conf[:USE_COLORIZE] = false` (the
-# default value is `true`).
-# * Giving command-line option `--nocolorize`
-#
-#
-# ## Debugging
-#
-# Command-line option `-d` sets variables `$VERBOSE` and `$DEBUG` to `true`;
-# these have no effect on IRB output.
-#
-# ### Warnings
-#
-# Command-line option `-w` suppresses warnings.
-#
-# Command-line option `-W[*level*]` sets warning level;
-#
-# * 0=silence
-# * 1=medium
-# * 2=verbose
-#
-# ## Other Features
-#
-# ### Load Modules
-#
-# You can specify the names of modules that are to be required at startup.
-#
-# Array `conf.load_modules` determines the modules (if any) that are to be
-# required during session startup. The array is used only during session
-# startup, so the initial value is the only one that counts.
-#
-# The default initial value is `[]` (load no modules):
-#
-# irb(main):001> conf.load_modules
-# => []
-#
-# You can set the default initial value via:
-#
-# * Command-line option `-r`
-#
-# $ irb -r csv -r json
-# irb(main):001> conf.load_modules
-# => ["csv", "json"]
-#
-# * Hash entry `IRB.conf[:LOAD_MODULES] = *array*`:
-#
-# IRB.conf[:LOAD_MODULES] = %w[csv, json]
-#
-#
-# Note that the configuration file entry overrides the command-line options.
-#
-# ### RI Documentation Directories
-#
-# You can specify the paths to RI documentation directories that are to be
-# loaded (in addition to the default directories) at startup; see details about
-# RI by typing `ri --help`.
-#
-# Array `conf.extra_doc_dirs` determines the directories (if any) that are to be
-# loaded during session startup. The array is used only during session startup,
-# so the initial value is the only one that counts.
-#
-# The default initial value is `[]` (load no extra documentation):
-#
-# irb(main):001> conf.extra_doc_dirs
-# => []
-#
-# You can set the default initial value via:
-#
-# * Command-line option `--extra_doc_dir`
-#
-# $ irb --extra-doc-dir your_doc_dir --extra-doc-dir my_doc_dir
-# irb(main):001> conf.extra_doc_dirs
-# => ["your_doc_dir", "my_doc_dir"]
-#
-# * Hash entry `IRB.conf[:EXTRA_DOC_DIRS] = *array*`:
-#
-# IRB.conf[:EXTRA_DOC_DIRS] = %w[your_doc_dir my_doc_dir]
-#
-#
-# Note that the configuration file entry overrides the command-line options.
-#
-# ### IRB Name
-#
-# You can specify a name for IRB.
-#
-# The default initial value is `'irb'`:
-#
-# irb(main):001> conf.irb_name
-# => "irb"
+# Or, invoke irb with the above prompt mode by:
+#
+# irb --prompt my-prompt
+#
+# Constants +PROMPT_I+, +PROMPT_S+ and +PROMPT_C+ specify the format. In the
+# prompt specification, some special strings are available:
+#
+# %N # command name which is running
+# %m # to_s of main object (self)
+# %M # inspect of main object (self)
+# %l # type of string(", ', /, ]), `]' is inner %w[...]
+# %NNi # indent level. NN is digits and means as same as printf("%NNd").
+# # It can be omitted
+# %NNn # line number.
+# %% # %
+#
+# For instance, the default prompt mode is defined as follows:
+#
+# IRB.conf[:PROMPT_MODE][: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" # used to printf
+# }
+#
+# irb comes with a number of available modes:
+#
+# # :NULL:
+# # :PROMPT_I:
+# # :PROMPT_N:
+# # :PROMPT_S:
+# # :PROMPT_C:
+# # :RETURN: |
+# # %s
+# # :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
+# # :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:%i> '
+# # :PROMPT_N:
+# # :PROMPT_S:
+# # :PROMPT_C:
+# # :RETURN: |
+# # %s
+# # :AUTO_INDENT: true
+# # :XMP:
+# # :PROMPT_I:
+# # :PROMPT_N:
+# # :PROMPT_S:
+# # :PROMPT_C:
+# # :RETURN: |2
+# # ==>%s
+#
+# == Restrictions
+#
+# Because irb evaluates input immediately after it is syntactically complete,
+# the results may be slightly different than directly using Ruby.
+#
+# == IRB Sessions
#
-# You can set the default initial value via hash entry `IRB.conf[:IRB_NAME] =
-# *string*`:
-#
-# IRB.conf[:IRB_NAME] = 'foo'
-#
-# ### Application Name
-#
-# You can specify an application name for the IRB session.
-#
-# The default initial value is `'irb'`:
-#
-# irb(main):001> conf.ap_name
-# => "irb"
-#
-# You can set the default initial value via hash entry `IRB.conf[:AP_NAME] =
-# *string*`:
-#
-# IRB.conf[:AP_NAME] = 'my_ap_name'
-#
-# ### Configuration Monitor
-#
-# You can monitor changes to the configuration by assigning a proc to
-# `IRB.conf[:IRB_RC]` in the configuration file:
-#
-# IRB.conf[:IRB_RC] = proc {|conf| puts conf.class }
-#
-# Each time the configuration is changed, that proc is called with argument
-# `conf`:
-#
-# ### Encodings
+# IRB has a special feature, that allows you to manage many sessions at once.
#
-# Command-line option `-E *ex*[:*in*]` sets initial external (ex) and internal
-# (in) encodings.
+# You can create new sessions with Irb.irb, and get a list of current sessions
+# with the +jobs+ command in the prompt.
#
-# Command-line option `-U` sets both to UTF-8.
+# === Commands
#
-# ### Commands
+# JobManager provides commands to handle the current sessions:
#
-# Please use the `help` command to see the list of available commands.
+# jobs # List of current sessions
+# fg # Switches to the session of the given number
+# kill # Kills the session with the given number
#
-# ### IRB Sessions
+# The +exit+ command, or ::irb_exit, will quit the current session and call any
+# exit hooks with IRB.irb_at_exit.
#
-# IRB has a special feature, that allows you to manage many sessions at once.
+# A few commands for loading files within the session are also available:
#
-# You can create new sessions with Irb.irb, and get a list of current sessions
-# with the `jobs` command in the prompt.
+# +source+::
+# Loads a given file in the current session and displays the source lines,
+# see IrbLoader#source_file
+# +irb_load+::
+# Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
+# +irb_require+::
+# Loads the given file similarly to Kernel#require
#
-# #### Configuration
+# === Configuration
#
# The command line options, or IRB.conf, specify the default behavior of
# Irb.irb.
#
-# On the other hand, each conf in IRB@Command-Line+Options is used to
+# On the other hand, each conf in IRB@Command+line+options is used to
# individually configure IRB.irb.
#
-# If a proc is set for `IRB.conf[:IRB_RC]`, its will be invoked after execution
+# If a proc is set for <code>IRB.conf[:IRB_RC]</code>, its will be invoked after execution
# of that proc with the context of the current session as its argument. Each
# session can be configured using this mechanism.
#
-# #### Session variables
+# === Session variables
#
# There are a few variables in every Irb session that can come in handy:
#
-# `_`
-# : The value command executed, as a local variable
-# `__`
-# : The history of evaluated commands. Available only if
-# `IRB.conf[:EVAL_HISTORY]` is not `nil` (which is the default). See also
-# IRB::Context#eval_history= and IRB::History.
-# `__[line_no]`
-# : Returns the evaluation value at the given line number, `line_no`. If
-# `line_no` is a negative, the return value `line_no` many lines before the
-# most recent return value.
-#
-#
-# ## Restrictions
-#
-# Ruby code typed into IRB behaves the same as Ruby code in a file, except that:
-#
-# * Because IRB evaluates input immediately after it is syntactically
-# complete, some results may be slightly different.
-# * Forking may not be well behaved.
-#
+# <code>_</code>::
+# The value command executed, as a local variable
+# <code>__</code>::
+# The history of evaluated commands. Available only if
+# <code>IRB.conf[:EVAL_HISTORY]</code> is not +nil+ (which is the default).
+# See also IRB::Context#eval_history= and IRB::History.
+# <code>__[line_no]</code>::
+# Returns the evaluation value at the given line number, +line_no+.
+# If +line_no+ is a negative, the return value +line_no+ many lines before
+# the most recent return value.
+#
+# === Example using IRB Sessions
+#
+# # invoke a new session
+# irb(main):001:0> irb
+# # list open sessions
+# irb.1(main):001:0> jobs
+# #0->irb on main (#<Thread:0x400fb7e4> : stop)
+# #1->irb#1 on main (#<Thread:0x40125d64> : running)
+#
+# # change the active session
+# irb.1(main):002:0> fg 0
+# # define class Foo in top-level session
+# irb(main):002:0> class Foo;end
+# # invoke a new session with the context of Foo
+# irb(main):003:0> irb Foo
+# # define Foo#foo
+# irb.2(Foo):001:0> def foo
+# irb.2(Foo):002:1> print 1
+# irb.2(Foo):003:1> end
+#
+# # change the active session
+# irb.2(Foo):004:0> fg 0
+# # list open sessions
+# irb(main):004:0> jobs
+# #0->irb on main (#<Thread:0x400fb7e4> : running)
+# #1->irb#1 on main (#<Thread:0x40125d64> : stop)
+# #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
+# # check if Foo#foo is available
+# irb(main):005:0> Foo.instance_methods #=> [:foo, ...]
+#
+# # change the active session
+# irb(main):006:0> fg 2
+# # define Foo#bar in the context of Foo
+# irb.2(Foo):005:0> def bar
+# irb.2(Foo):006:1> print "bar"
+# irb.2(Foo):007:1> end
+# irb.2(Foo):010:0> Foo.instance_methods #=> [:bar, :foo, ...]
+#
+# # change the active session
+# irb.2(Foo):011:0> fg 0
+# irb(main):007:0> f = Foo.new #=> #<Foo:0x4010af3c>
+# # invoke a new session with the context of f (instance of Foo)
+# irb(main):008:0> irb f
+# # list open sessions
+# irb.3(<Foo:0x4010af3c>):001:0> jobs
+# #0->irb on main (#<Thread:0x400fb7e4> : stop)
+# #1->irb#1 on main (#<Thread:0x40125d64> : stop)
+# #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
+# #3->irb#3 on #<Foo:0x4010af3c> (#<Thread:0x4010a1e0> : running)
+# # evaluate f.foo
+# irb.3(<Foo:0x4010af3c>):002:0> foo #=> 1 => nil
+# # evaluate f.bar
+# irb.3(<Foo:0x4010af3c>):003:0> bar #=> bar => nil
+# # kill jobs 1, 2, and 3
+# irb.3(<Foo:0x4010af3c>):004:0> kill 1, 2, 3
+# # list open sessions, should only include main session
+# irb(main):009:0> jobs
+# #0->irb on main (#<Thread:0x400fb7e4> : running)
+# # quit irb
+# irb(main):010:0> exit
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
- # irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
- # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
- def IRB.CurrentContext # :nodoc:
+ # irb
+ # irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
+ # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
+ def IRB.CurrentContext
IRB.conf[:MAIN_CONTEXT]
end
- # Initializes IRB and creates a new Irb.irb object at the `TOPLEVEL_BINDING`
+ # Initializes IRB and creates a new Irb.irb object at the +TOPLEVEL_BINDING+
def IRB.start(ap_path = nil)
STDOUT.sync = true
$0 = File::basename(ap_path, ".rb") if ap_path
@@ -904,49 +421,64 @@ 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(*) # :nodoc:
- throw :IRB_EXIT, false
+ def IRB.irb_exit(irb, ret)
+ throw :IRB_EXIT, ret
end
# Aborts then interrupts irb.
#
- # Will raise an Abort exception, or the given `exception`.
- def IRB.irb_abort(irb, exception = Abort) # :nodoc:
+ # Will raise an Abort exception, or the given +exception+.
+ def IRB.irb_abort(irb, exception = Abort)
irb.context.thread.raise exception, "abort then interrupt!"
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 = '...'
- CONTROL_CHARACTERS_PATTERN = "\x00-\x1F"
-
- # Returns the current context of this irb session
- attr_reader :context
- # The lexer used by this irb session
- attr_accessor :scanner
-
- attr_reader :from_binding
+ # "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
# Creates a new irb session
- def initialize(workspace = nil, input_method = nil, from_binding: false)
- @from_binding = from_binding
+ def initialize(workspace = nil, input_method = nil)
@context = Context.new(self, workspace, input_method)
- @context.workspace.load_helper_methods_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)
@@ -955,101 +487,108 @@ module IRB
end
end
- def debug_readline(binding)
- workspace = IRB::WorkSpace.new(binding)
- context.replace_workspace(workspace)
- context.workspace.load_helper_methods_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 = nil
- forced_exit = catch(:IRB_EXIT) do
- 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 resetting the counter
- context.io.reset_history_counter
-
- begin
- input = eval_input
- ensure
- context.io.save_history
- end
- else
- input = eval_input
- end
- false
- end
-
- Kernel.exit if forced_exit
-
- 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]
- prev_context = conf[:MAIN_CONTEXT]
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
begin
- if defined?(RubyVM.keep_script_lines)
- keep_script_lines_backup = RubyVM.keep_script_lines
- RubyVM.keep_script_lines = true
- end
-
- forced_exit = catch(:IRB_EXIT) do
+ catch(:IRB_EXIT) do
eval_input
end
ensure
- # Do not restore to nil. It will cause IRB crash when used with threads.
- IRB.conf[:MAIN_CONTEXT] = prev_context if prev_context
-
- RubyVM.keep_script_lines = keep_script_lines_backup if defined?(RubyVM.keep_script_lines)
trap("SIGINT", prev_trap)
conf[:AT_EXIT].each{|hook| hook.call}
-
- context.io.save_history if save_history
- Kernel.exit if forced_exit
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, 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
@@ -1057,157 +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
- else
- print "\n" if @context.prompting?
- 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
- return code if 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
- yield build_statement(code), @line_no
- @line_no += code.count("\n")
- rescue RubyLex::TerminateLineInput
- end
- end
-
- def build_statement(code)
- if code.match?(/\A\n*\z/)
- return Statement::EmptyInput.new
- end
-
- code.force_encoding(@context.io.encoding)
- if (command, arg = parse_command(code))
- command_class = Command.load_command(command)
- Statement::Command.new(code, command_class, arg)
- else
- is_assignment_expression = @scanner.assignment_expression?(code, local_variables: @context.local_variables)
- Statement::Expression.new(code, is_assignment_expression)
- end
- end
-
- def parse_command(code)
- command_name, arg = code.strip.split(/\s+/, 2)
- return unless code.lines.size == 1 && command_name
-
- arg ||= ''
- command = command_name.to_sym
- # Command aliases are always command. example: $, @
- if (alias_name = @context.command_aliases[command])
- return [alias_name, arg]
- end
-
- # Check visibility
- public_method = !!Kernel.instance_method(:public_method).bind_call(@context.main, command) rescue false
- private_method = !public_method && !!Kernel.instance_method(:method).bind_call(@context.main, command) rescue false
- if Command.execute_as_command?(command, public_method: public_method, private_method: private_method)
- [command, arg]
- end
- end
-
- def command?(code)
- !!parse_command(code)
- 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
+ rescue Exception => exc
else
- next true if 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|
- 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)
+ exc = nil
+ next
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
@@ -1242,75 +641,60 @@ module IRB
end
def handle_exception(exc)
- if exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
+ if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
!(SyntaxError === exc) && !(EncodingError === exc)
# The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno.
irb_bug = true
else
irb_bug = false
- # To support backtrace filtering while utilizing Exception#full_message, we need to clone
- # the exception to avoid modifying the original exception's backtrace.
- exc = exc.clone
- filtered_backtrace = exc.backtrace.map { |l| @context.workspace.filter_backtrace(l) }.compact
- backtrace_filter = IRB.conf[:BACKTRACE_FILTER]
-
- if backtrace_filter
- if backtrace_filter.respond_to?(:call)
- filtered_backtrace = backtrace_filter.call(filtered_backtrace)
- else
- warn "IRB.conf[:BACKTRACE_FILTER] #{backtrace_filter} should respond to `call` method"
- end
- end
-
- exc.set_backtrace(filtered_backtrace)
end
- highlight = Color.colorable?
-
- order =
+ if exc.backtrace
+ order = nil
if RUBY_VERSION < '3.0.0'
- STDOUT.tty? ? :bottom : :top
+ if STDOUT.tty?
+ message = exc.full_message(order: :bottom)
+ order = :bottom
+ else
+ message = exc.full_message(order: :top)
+ order = :top
+ end
else # '3.0.0' <= RUBY_VERSION
- :top
+ message = exc.full_message(order: :top)
+ order = :top
end
-
- message = exc.full_message(order: order, highlight: highlight)
- message = convert_invalid_byte_sequence(message, exc.message.encoding)
- message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
- message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
- case order
- when :top
- lines = m.split("\n")
- when :bottom
- lines = m.split("\n").reverse
- end
- unless irb_bug
- if lines.size > @context.back_trace_limit
- omit = lines.size - @context.back_trace_limit
- lines = lines[0..(@context.back_trace_limit - 1)]
- lines << "\t... %d levels..." % omit
+ message = convert_invalid_byte_sequence(message, exc.message.encoding)
+ message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
+ message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
+ case order
+ when :top
+ lines = m.split("\n")
+ when :bottom
+ lines = m.split("\n").reverse
end
- end
- lines = lines.reverse if order == :bottom
- lines.map{ |l| l + "\n" }.join
- }
- # The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object.
- message = message.gsub(/\(irb\):(?<num>\d+):in (?<open_quote>[`'])<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in #{$~[:open_quote]}<main>'" }
- puts message
- puts 'Maybe IRB bug!' if irb_bug
- rescue Exception => handler_exc
- begin
- puts exc.inspect
- puts "backtraces are hidden because #{handler_exc} was raised when processing them"
- rescue Exception
- puts 'Uninspectable exception occurred'
- end
+ unless irb_bug
+ lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact
+ if lines.size > @context.back_trace_limit
+ omit = lines.size - @context.back_trace_limit
+ lines = lines[0..(@context.back_trace_limit - 1)]
+ lines << "\t... %d levels..." % omit
+ end
+ end
+ lines = lines.reverse if order == :bottom
+ lines.map{ |l| l + "\n" }.join
+ }
+ # The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object.
+ message = message.gsub(/\(irb\):(?<num>\d+):in `<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in `<main>'" }
+ puts message
+ end
+ print "Maybe IRB bug!\n" if irb_bug
end
- # Evaluates the given block using the given `path` as the Context#irb_path and
- # `name` as the Context#irb_name.
+ # Evaluates the given block using the given +path+ as the Context#irb_path
+ # and +name+ as the Context#irb_name.
#
- # Used by the irb command `source`, see IRB@IRB+Sessions for more information.
+ # Used by the irb command +source+, see IRB@IRB+Sessions for more
+ # information.
def suspend_name(path = nil, name = nil)
@context.irb_path, back_path = path, @context.irb_path if path
@context.irb_name, back_name = name, @context.irb_name if name
@@ -1322,22 +706,25 @@ module IRB
end
end
- # Evaluates the given block using the given `workspace` as the
+ # Evaluates the given block using the given +workspace+ as the
# Context#workspace.
#
- # Used by the irb command `irb_load`, see IRB@IRB+Sessions for more information.
+ # Used by the irb command +irb_load+, see IRB@IRB+Sessions for more
+ # information.
def suspend_workspace(workspace)
- current_workspace = @context.workspace
- @context.replace_workspace(workspace)
- yield
- ensure
- @context.replace_workspace current_workspace
+ @context.workspace, back_workspace = workspace, @context.workspace
+ begin
+ yield back_workspace
+ ensure
+ @context.workspace = back_workspace
+ end
end
- # Evaluates the given block using the given `input_method` as the Context#io.
+ # Evaluates the given block using the given +input_method+ as the
+ # Context#io.
#
- # Used by the irb commands `source` and `irb_load`, see IRB@IRB+Sessions for
- # more information.
+ # Used by the irb commands +source+ and +irb_load+, see IRB@IRB+Sessions
+ # for more information.
def suspend_input_method(input_method)
back_io = @context.io
@context.instance_eval{@io = input_method}
@@ -1348,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?
@@ -1370,7 +767,7 @@ module IRB
end
end
- # Evaluates the given block using the given `status`.
+ # Evaluates the given block using the given +status+.
def signal_status(status)
return yield if @signal_status == :IN_LOAD
@@ -1383,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")
@@ -1412,16 +848,15 @@ module IRB
end
end
end
-
if multiline_p && @context.newline_before_multiline_output?
- str = "\n" + str
+ printf @context.return_format, "\n#{str}"
+ else
+ printf @context.return_format, str
end
-
- Pager.page_content(format(@context.return_format, str), retain_content: true)
end
- # Outputs the local variables to this current session, including #signal_status
- # and #context, using IRB::Locale.
+ # Outputs the local variables to this current session, including
+ # #signal_status and #context, using IRB::Locale.
def inspect
ary = []
for iv in instance_variables
@@ -1437,94 +872,60 @@ 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"
- main_str = @context.main.to_s rescue "!#{$!.class}"
- truncate_prompt_main(main_str)
- when "M"
- main_str = @context.main.inspect rescue "!#{$!.class}"
- truncate_prompt_main(main_str)
- 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 "%"
- "%" unless $1
- 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
class Binding
- # Opens an IRB session where `binding.irb` is called which allows for
- # interactive debugging. You can call any methods or variables available in the
- # current scope, and mutate state if you need to.
+ # Opens an IRB session where +binding.irb+ is called which allows for
+ # interactive debugging. You can call any methods or variables available in
+ # the current scope, and mutate state if you need to.
+ #
#
- # Given a Ruby file called `potato.rb` containing the following code:
+ # Given a Ruby file called +potato.rb+ containing the following code:
#
# class Potato
# def initialize
@@ -1536,8 +937,8 @@ class Binding
#
# Potato.new
#
- # Running `ruby potato.rb` will open an IRB session where `binding.irb` is
- # called, and you will see the following:
+ # Running <code>ruby potato.rb</code> will open an IRB session where
+ # +binding.irb+ is called, and you will see the following:
#
# $ ruby potato.rb
#
@@ -1567,42 +968,22 @@ class Binding
# irb(#<Potato:0x00007feea1916670>):004:0> @cooked = true
# => true
#
- # You can exit the IRB session with the `exit` command. Note that exiting will
- # resume execution where `binding.irb` had paused it, as you can see from the
+ # You can exit the IRB session with the +exit+ command. Note that exiting will
+ # resume execution where +binding.irb+ had paused it, as you can see from the
# output printed to standard output in this example:
#
# irb(#<Potato:0x00007feea1916670>):005:0> exit
# Cooked potato: true
#
- # See IRB 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: []) unless IRB.initialized?
- # Create a new workspace using the current binding
+ IRB.setup(source_location[0], argv: [])
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.replace_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, from_binding: true)
- 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/backtrace.rb b/lib/irb/cmd/backtrace.rb
new file mode 100644
index 0000000000..f632894618
--- /dev/null
+++ b/lib/irb/cmd/backtrace.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Backtrace < DebugCommand
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(*args)
+ super(pre_cmds: ["backtrace", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/break.rb b/lib/irb/cmd/break.rb
new file mode 100644
index 0000000000..df259a90ca
--- /dev/null
+++ b/lib/irb/cmd/break.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Break < DebugCommand
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(args = nil)
+ super(pre_cmds: "break #{args}")
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/catch.rb b/lib/irb/cmd/catch.rb
new file mode 100644
index 0000000000..40b62c7533
--- /dev/null
+++ b/lib/irb/cmd/catch.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Catch < DebugCommand
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(*args)
+ super(pre_cmds: ["catch", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/chws.rb b/lib/irb/cmd/chws.rb
new file mode 100644
index 0000000000..7c84ba0a4b
--- /dev/null
+++ b/lib/irb/cmd/chws.rb
@@ -0,0 +1,42 @@
+# 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"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+
+ class CurrentWorkingWorkspace < Nop
+ category "IRB"
+ description "Show the current workspace."
+
+ def execute(*obj)
+ irb_context.main
+ end
+ end
+
+ class ChangeWorkspace < Nop
+ category "IRB"
+ description "Change the current workspace to an object."
+
+ def execute(*obj)
+ irb_context.change_workspace(*obj)
+ irb_context.main
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/continue.rb b/lib/irb/cmd/continue.rb
new file mode 100644
index 0000000000..9136177eef
--- /dev/null
+++ b/lib/irb/cmd/continue.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Continue < DebugCommand
+ def execute(*args)
+ super(do_cmds: ["continue", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/debug.rb b/lib/irb/cmd/debug.rb
new file mode 100644
index 0000000000..7d39b9fa27
--- /dev/null
+++ b/lib/irb/cmd/debug.rb
@@ -0,0 +1,136 @@
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Debug < Nop
+ category "Debugging"
+ description "Start the debugger of debug.gem."
+
+ BINDING_IRB_FRAME_REGEXPS = [
+ '<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)
+ unless binding_irb?
+ puts "`debug` command is only available when IRB is started with binding.irb"
+ return
+ end
+
+ 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
+
+ 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
+
+ def binding_irb?
+ caller.any? do |frame|
+ BINDING_IRB_FRAME_REGEXPS.any? do |regexp|
+ frame.match?(regexp)
+ 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
+ def self.category
+ "Debugging"
+ end
+
+ def self.description
+ command_name = self.name.split("::").last.downcase
+ "Start the debugger of debug.gem and run its `#{command_name}` command."
+ end
+ end
+ end
+end
diff --git a/lib/irb/cmd/delete.rb b/lib/irb/cmd/delete.rb
new file mode 100644
index 0000000000..aeb26d2572
--- /dev/null
+++ b/lib/irb/cmd/delete.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Delete < DebugCommand
+ def execute(*args)
+ super(pre_cmds: ["delete", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/edit.rb b/lib/irb/cmd/edit.rb
new file mode 100644
index 0000000000..0103891cf4
--- /dev/null
+++ b/lib/irb/cmd/edit.rb
@@ -0,0 +1,61 @@
+require 'shellwords'
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Edit < Nop
+ category "Misc"
+ description 'Open a file with the editor command defined with `ENV["EDITOR"]`.'
+
+ class << self
+ def transform_args(args)
+ # Return a string literal as is for backward compatibility
+ if args.nil? || args.empty? || string_literal?(args)
+ args
+ else # Otherwise, consider the input as a String for convenience
+ args.strip.dump
+ end
+ end
+ end
+
+ def execute(*args)
+ path = args.first
+
+ if path.nil? && (irb_path = @irb_context.irb_path)
+ path = irb_path
+ end
+
+ if !File.exist?(path)
+ require_relative "show_source"
+
+ source =
+ begin
+ 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 && File.exist?(source.file)
+ path = source.file
+ else
+ puts "Can not find file: #{path}"
+ return
+ end
+ end
+
+ if editor = ENV['EDITOR']
+ puts "command: '#{editor}'"
+ puts " path: #{path}"
+ system(*Shellwords.split(editor), path)
+ else
+ puts "Can not find editor setting: ENV['EDITOR']"
+ end
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/finish.rb b/lib/irb/cmd/finish.rb
new file mode 100644
index 0000000000..29f100feb5
--- /dev/null
+++ b/lib/irb/cmd/finish.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Finish < DebugCommand
+ def execute(*args)
+ super(do_cmds: ["finish", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+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
new file mode 100644
index 0000000000..2a135cdb14
--- /dev/null
+++ b/lib/irb/cmd/help.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: false
+#
+# help.rb - helper using ri
+# $Release Version: 0.9.6$
+# $Revision$
+#
+# --
+#
+#
+#
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ 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
+
+ category "Context"
+ description "Enter the mode to look up RI documents."
+
+ def execute(*names)
+ 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/info.rb b/lib/irb/cmd/info.rb
new file mode 100644
index 0000000000..2c0a32b34f
--- /dev/null
+++ b/lib/irb/cmd/info.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Info < DebugCommand
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(*args)
+ super(pre_cmds: ["info", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/irb_info.rb b/lib/irb/cmd/irb_info.rb
new file mode 100644
index 0000000000..da11e8d40b
--- /dev/null
+++ b/lib/irb/cmd/irb_info.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: false
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class IrbInfo < Nop
+ category "IRB"
+ description "Show information about IRB."
+
+ def execute
+ 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
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/load.rb b/lib/irb/cmd/load.rb
new file mode 100644
index 0000000000..2897bbd975
--- /dev/null
+++ b/lib/irb/cmd/load.rb
@@ -0,0 +1,82 @@
+# 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"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class LoaderCommand < Nop
+ include IrbLoader
+
+ def raise_cmd_argument_error
+ raise CommandArgumentError.new("Please specify the file name.")
+ end
+ end
+
+ class Load < LoaderCommand
+ category "IRB"
+ description "Load a Ruby file."
+
+ def execute(file_name = nil, priv = nil)
+ raise_cmd_argument_error unless file_name
+ irb_load(file_name, priv)
+ end
+ end
+
+ class Require < LoaderCommand
+ category "IRB"
+ description "Require a Ruby file."
+ def execute(file_name = nil)
+ raise_cmd_argument_error unless file_name
+
+ rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
+ return false if $".find{|f| f =~ rex}
+
+ case file_name
+ when /\.rb$/
+ begin
+ if irb_load(file_name)
+ $".push file_name
+ return true
+ end
+ rescue LoadError
+ end
+ when /\.(so|o|sl)$/
+ return ruby_require(file_name)
+ end
+
+ begin
+ irb_load(f = file_name + ".rb")
+ $".push f
+ return true
+ rescue LoadError
+ return ruby_require(file_name)
+ end
+ end
+ end
+
+ class Source < LoaderCommand
+ category "IRB"
+ description "Loads a given file in the current session."
+
+ def execute(file_name = nil)
+ raise_cmd_argument_error unless file_name
+
+ source_file(file_name)
+ end
+ end
+ end
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/ls.rb b/lib/irb/cmd/ls.rb
new file mode 100644
index 0000000000..b65fae2bf1
--- /dev/null
+++ b/lib/irb/cmd/ls.rb
@@ -0,0 +1,116 @@
+# frozen_string_literal: true
+
+require "reline"
+require_relative "nop"
+require_relative "../color"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Ls < Nop
+ category "Context"
+ description "Show methods, constants, and variables. `-g [query]` or `-G [query]` allows you to filter out the output."
+
+ def self.transform_args(args)
+ if match = args&.match(/\A(?<args>.+\s|)(-g|-G)\s+(?<grep>[^\s]+)\s*\n\z/)
+ args = match[:args]
+ "#{args}#{',' unless args.chomp.empty?} grep: /#{match[:grep]}/"
+ else
+ args
+ end
+ end
+
+ def execute(*arg, grep: nil)
+ o = Output.new(grep: grep)
+
+ obj = arg.empty? ? irb_context.workspace.main : arg.first
+ locals = arg.empty? ? irb_context.workspace.binding.local_variables : []
+ klass = (obj.class == Class || obj.class == Module ? obj : obj.class)
+
+ o.dump("constants", obj.constants) if obj.respond_to?(:constants)
+ dump_methods(o, klass, obj)
+ o.dump("instance variables", obj.instance_variables)
+ o.dump("class variables", klass.class_variables)
+ o.dump("locals", locals)
+ nil
+ end
+
+ def dump_methods(o, klass, obj)
+ singleton_class = begin obj.singleton_class; rescue TypeError; nil end
+ 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 = 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.reverse
+ end
+
+ class Output
+ MARGIN = " "
+
+ def initialize(grep: nil)
+ @grep = grep
+ @line_width = screen_width - MARGIN.length # right padding
+ end
+
+ def dump(name, strs)
+ strs = strs.grep(@grep) if @grep
+ strs = strs.sort
+ return if strs.empty?
+
+ # Attempt a single line
+ print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
+ if fits_on_line?(strs, cols: strs.size, offset: "#{name}: ".length)
+ puts strs.join(MARGIN)
+ return
+ end
+ puts
+
+ # Dump with the largest # of columns that fits on a line
+ cols = strs.size
+ until fits_on_line?(strs, cols: cols, offset: MARGIN.length) || cols == 1
+ cols -= 1
+ end
+ widths = col_widths(strs, cols: cols)
+ strs.each_slice(cols) do |ss|
+ puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
+ end
+ end
+
+ private
+
+ def fits_on_line?(strs, cols:, offset: 0)
+ width = col_widths(strs, cols: cols).sum + MARGIN.length * (cols - 1)
+ width <= @line_width - offset
+ end
+
+ def col_widths(strs, cols:)
+ cols.times.map do |col|
+ (col...strs.size).step(cols).map do |i|
+ strs[i].length
+ end.max
+ end
+ end
+
+ def screen_width
+ Reline.get_screen_size.last
+ rescue Errno::EINVAL # in `winsize': Invalid argument - <STDIN>
+ 80
+ end
+ end
+ private_constant :Output
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/measure.rb b/lib/irb/cmd/measure.rb
new file mode 100644
index 0000000000..9122e2dac9
--- /dev/null
+++ b/lib/irb/cmd/measure.rb
@@ -0,0 +1,48 @@
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Measure < Nop
+ category "Misc"
+ description "`measure` enables the mode to measure processing time. `measure :off` disables it."
+
+ def initialize(*args)
+ super(*args)
+ end
+
+ def execute(type = nil, arg = nil, &block)
+ # Please check IRB.init_config in lib/irb/init.rb that sets
+ # IRB.conf[:MEASURE_PROC] to register default "measure" methods,
+ # "measure :time" (abbreviated as "measure") and "measure :stackprof".
+ case type
+ when :off
+ IRB.conf[:MEASURE] = nil
+ IRB.unset_measure_callback(arg)
+ when :list
+ IRB.conf[:MEASURE_CALLBACKS].each do |type_name, _, arg_val|
+ puts "- #{type_name}" + (arg_val ? "(#{arg_val.inspect})" : '')
+ end
+ when :on
+ IRB.conf[:MEASURE] = true
+ added = IRB.set_measure_callback(type, arg)
+ puts "#{added[0]} is added." if added
+ else
+ if block_given?
+ IRB.conf[:MEASURE] = true
+ added = IRB.set_measure_callback(&block)
+ puts "#{added[0]} is added." if added
+ else
+ IRB.conf[:MEASURE] = true
+ added = IRB.set_measure_callback(type, arg)
+ puts "#{added[0]} is added." if added
+ end
+ end
+ nil
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/next.rb b/lib/irb/cmd/next.rb
new file mode 100644
index 0000000000..d29c82e7fc
--- /dev/null
+++ b/lib/irb/cmd/next.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Next < DebugCommand
+ def execute(*args)
+ super(do_cmds: ["next", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/nop.rb b/lib/irb/cmd/nop.rb
index 9d2e3c4d47..c616c054a8 100644
--- a/lib/irb/cmd/nop.rb
+++ b/lib/irb/cmd/nop.rb
@@ -1,4 +1,71 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
+#
+# nop.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+module IRB
+ # :stopdoc:
-# This file is just a placeholder for backward-compatibility.
-# Please require 'irb' and inherit your command from `IRB::Command::Base` instead.
+ module ExtendCommand
+ class CommandArgumentError < StandardError; end
+
+ class Nop
+ class << self
+ def category(category = nil)
+ @category = category if category
+ @category
+ end
+
+ def description(description = nil)
+ @description = description if description
+ @description
+ end
+
+ private
+
+ def string_literal?(args)
+ sexp = Ripper.sexp(args)
+ sexp && sexp.size == 2 && sexp.last&.first&.first == :string_literal
+ end
+ end
+
+ 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(conf)
+ @irb_context = conf
+ end
+
+ attr_reader :irb_context
+
+ def irb
+ @irb_context.irb
+ end
+
+ def execute(*opts)
+ #nop
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/pushws.rb b/lib/irb/cmd/pushws.rb
new file mode 100644
index 0000000000..41d2e705f1
--- /dev/null
+++ b/lib/irb/cmd/pushws.rb
@@ -0,0 +1,51 @@
+# 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"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Workspaces < Nop
+ category "IRB"
+ description "Show workspaces."
+
+ def execute(*obj)
+ irb_context.workspaces.collect{|ws| ws.main}
+ end
+ end
+
+ class PushWorkspace < Workspaces
+ category "IRB"
+ description "Push an object to the workspace stack."
+
+ def execute(*obj)
+ irb_context.push_workspace(*obj)
+ super
+ end
+ end
+
+ class PopWorkspace < Workspaces
+ category "IRB"
+ description "Pop a workspace from the workspace stack."
+
+ def execute(*obj)
+ irb_context.pop_workspace(*obj)
+ super
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/show_cmds.rb b/lib/irb/cmd/show_cmds.rb
new file mode 100644
index 0000000000..acced27d48
--- /dev/null
+++ b/lib/irb/cmd/show_cmds.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require "stringio"
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class ShowCmds < Nop
+ category "IRB"
+ description "List all available commands and their description."
+
+ def execute(*args)
+ commands_info = IRB::ExtendCommandBundle.all_commands_info
+ commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
+ longest_cmd_name_length = commands_info.map { |c| c[:display_name] }.max { |a, b| a.length <=> b.length }.length
+
+ output = StringIO.new
+
+ commands_grouped_by_categories.each do |category, cmds|
+ output.puts Color.colorize(category, [:BOLD])
+
+ cmds.each do |cmd|
+ output.puts " #{cmd[:display_name].to_s.ljust(longest_cmd_name_length)} #{cmd[:description]}"
+ end
+
+ output.puts
+ end
+
+ puts output.string
+
+ nil
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/show_source.rb b/lib/irb/cmd/show_source.rb
new file mode 100644
index 0000000000..ea700be4bf
--- /dev/null
+++ b/lib/irb/cmd/show_source.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require_relative "nop"
+require_relative "../color"
+require_relative "../ruby-lex"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class ShowSource < Nop
+ category "Context"
+ description "Show the source code of a given method or constant."
+
+ 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
+
+ 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)
+ unless str.is_a?(String)
+ puts "Error: Expected a string but got #{str.inspect}"
+ return
+ end
+
+ 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}"
+ end
+ nil
+ end
+
+ private
+
+ # @param [IRB::ExtendCommand::ShowSource::Source] source
+ def show_source(source)
+ 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/step.rb b/lib/irb/cmd/step.rb
new file mode 100644
index 0000000000..2bc74a9d79
--- /dev/null
+++ b/lib/irb/cmd/step.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Step < DebugCommand
+ def execute(*args)
+ super(do_cmds: ["step", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/subirb.rb b/lib/irb/cmd/subirb.rb
new file mode 100644
index 0000000000..699b35fcb4
--- /dev/null
+++ b/lib/irb/cmd/subirb.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: false
+# multi.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class MultiIRBCommand < Nop
+ def initialize(conf)
+ super
+ extend_irb_context
+ end
+
+ private
+
+ def extend_irb_context
+ # this extension patches IRB context like IRB.CurrentContext
+ require_relative "../ext/multi-irb"
+ end
+ end
+
+ class IrbCommand < MultiIRBCommand
+ category "IRB"
+ description "Start a child IRB."
+
+ def execute(*obj)
+ IRB.irb(nil, *obj)
+ end
+ end
+
+ class Jobs < MultiIRBCommand
+ category "IRB"
+ description "List of current sessions."
+
+ def execute
+ IRB.JobManager
+ end
+ end
+
+ class Foreground < MultiIRBCommand
+ category "IRB"
+ description "Switches to the session of the given number."
+
+ def execute(key = nil)
+ 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 "IRB"
+ description "Kills the session with the given number."
+
+ def execute(*keys)
+ IRB.JobManager.kill(*keys)
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/whereami.rb b/lib/irb/cmd/whereami.rb
new file mode 100644
index 0000000000..8f56ba073d
--- /dev/null
+++ b/lib/irb/cmd/whereami.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Whereami < Nop
+ category "Context"
+ description "Show the source code around binding.irb again."
+
+ def execute(*)
+ code = irb_context.workspace.code_around_binding
+ if code
+ puts code
+ else
+ puts "The current context doesn't have code."
+ end
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/color.rb b/lib/irb/color.rb
index fca942b28b..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__'],
@@ -79,12 +77,12 @@ module IRB # :nodoc:
class << self
def colorable?
- supported = $stdout.tty? && (/mswin|mingw/.match?(RUBY_PLATFORM) || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
+ supported = $stdout.tty? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
# because ruby/debug also uses irb's color module selectively,
# irb won't be activated in that case.
if IRB.respond_to?(:conf)
- supported && !!IRB.conf.fetch(:USE_COLORIZE, true)
+ supported && IRB.conf.fetch(:USE_COLORIZE, true)
else
supported
end
@@ -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/command.rb b/lib/irb/command.rb
deleted file mode 100644
index 68a4b52727..0000000000
--- a/lib/irb/command.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/command.rb - irb command
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-require_relative "command/base"
-
-module IRB # :nodoc:
- module Command
- @commands = {}
-
- class << self
- attr_reader :commands
-
- # Registers a command with the given name.
- # Aliasing is intentionally not supported at the moment.
- def register(name, command_class)
- @commands[name.to_sym] = [command_class, []]
- end
- end
- end
-end
diff --git a/lib/irb/command/backtrace.rb b/lib/irb/command/backtrace.rb
deleted file mode 100644
index 687bb075ac..0000000000
--- a/lib/irb/command/backtrace.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Backtrace < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "backtrace #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/base.rb b/lib/irb/command/base.rb
deleted file mode 100644
index 1d406630a2..0000000000
--- a/lib/irb/command/base.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-#
-# nop.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-module IRB
- # :stopdoc:
-
- module Command
- class CommandArgumentError < StandardError; end
-
- def self.extract_ruby_args(*args, **kwargs)
- throw :EXTRACT_RUBY_ARGS, [args, kwargs]
- end
-
- class Base
- class << self
- def category(category = nil)
- @category = category if category
- @category || "No category"
- end
-
- def description(description = nil)
- @description = description if description
- @description || "No description provided."
- end
-
- def help_message(help_message = nil)
- @help_message = help_message if help_message
- @help_message
- end
-
- private
-
- def highlight(text)
- Color.colorize(text, [:BOLD, :BLUE])
- end
- end
-
- def self.execute(irb_context, arg)
- new(irb_context).execute(arg)
- rescue CommandArgumentError => e
- puts e.message
- end
-
- def initialize(irb_context)
- @irb_context = irb_context
- end
-
- attr_reader :irb_context
-
- def execute(arg)
- #nop
- end
- end
-
- Nop = Base
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/break.rb b/lib/irb/command/break.rb
deleted file mode 100644
index a8f81fe665..0000000000
--- a/lib/irb/command/break.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Break < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "break #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/catch.rb b/lib/irb/command/catch.rb
deleted file mode 100644
index 529dcbca5a..0000000000
--- a/lib/irb/command/catch.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Catch < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "catch #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/chws.rb b/lib/irb/command/chws.rb
deleted file mode 100644
index ef456d0961..0000000000
--- a/lib/irb/command/chws.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-#
-# change-ws.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-require_relative "../ext/change-ws"
-
-module IRB
- # :stopdoc:
-
- module Command
-
- class CurrentWorkingWorkspace < Base
- category "Workspace"
- description "Show the current workspace."
-
- def execute(_arg)
- puts "Current workspace: #{irb_context.main}"
- end
- end
-
- class ChangeWorkspace < Base
- category "Workspace"
- description "Change the current workspace to an object."
-
- def execute(arg)
- if arg.empty?
- irb_context.change_workspace
- else
- obj = eval(arg, irb_context.workspace.binding)
- irb_context.change_workspace(obj)
- end
-
- puts "Current workspace: #{irb_context.main}"
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/context.rb b/lib/irb/command/context.rb
deleted file mode 100644
index b4fc807343..0000000000
--- a/lib/irb/command/context.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class Context < Base
- category "IRB"
- description "Displays current configuration."
-
- def execute(_arg)
- # This command just displays the configuration.
- # Modifying the configuration is achieved by sending a message to IRB.conf.
- Pager.page_content(IRB.CurrentContext.inspect)
- end
- end
- end
-end
diff --git a/lib/irb/command/continue.rb b/lib/irb/command/continue.rb
deleted file mode 100644
index 0daa029b15..0000000000
--- a/lib/irb/command/continue.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Continue < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "continue #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/debug.rb b/lib/irb/command/debug.rb
deleted file mode 100644
index 8a091a49ed..0000000000
--- a/lib/irb/command/debug.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-require_relative "../debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Debug < Base
- category "Debugging"
- description "Start the debugger of debug.gem."
-
- def execute(_arg)
- execute_debug_command
- end
-
- def execute_debug_command(pre_cmds: nil, do_cmds: nil)
- pre_cmds = pre_cmds&.rstrip
- do_cmds = do_cmds&.rstrip
-
- 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 irb_context.from_binding?
- puts "Debugging commands are 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
-
- IRB::Debug.insert_debug_break(pre_cmds: pre_cmds, do_cmds: do_cmds)
-
- # exit current Irb#run call
- throw :IRB_EXIT
- end
- end
- end
-
- class DebugCommand < Debug
- def self.category
- "Debugging"
- end
-
- def self.description
- command_name = self.name.split("::").last.downcase
- "Start the debugger of debug.gem and run its `#{command_name}` command."
- end
- end
- end
-end
diff --git a/lib/irb/command/delete.rb b/lib/irb/command/delete.rb
deleted file mode 100644
index 2a57a4a3de..0000000000
--- a/lib/irb/command/delete.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Delete < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "delete #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/disable_irb.rb b/lib/irb/command/disable_irb.rb
deleted file mode 100644
index 0b00d0302b..0000000000
--- a/lib/irb/command/disable_irb.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class DisableIrb < Base
- category "IRB"
- description "Disable binding.irb."
-
- def execute(*)
- ::Binding.define_method(:irb) {}
- IRB.irb_exit
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/edit.rb b/lib/irb/command/edit.rb
deleted file mode 100644
index cb7e0c4873..0000000000
--- a/lib/irb/command/edit.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'shellwords'
-
-require_relative "../color"
-require_relative "../source_finder"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Edit < Base
- include RubyArgsExtractor
-
- category "Misc"
- description 'Open a file or source location.'
- help_message <<~HELP_MESSAGE
- Usage: edit [FILE or constant or method signature]
-
- Open a file in the editor specified in #{highlight('ENV["VISUAL"]')} or #{highlight('ENV["EDITOR"]')}
-
- - If no arguments are provided, IRB will attempt to open the file the current context was defined in.
- - If FILE is provided, IRB will open the file.
- - If a constant or method signature is provided, IRB will attempt to locate the source file and open it.
-
- Examples:
-
- edit
- edit foo.rb
- edit Foo
- edit Foo#bar
- HELP_MESSAGE
-
- def execute(arg)
- # Accept string literal for backward compatibility
- path = unwrap_string_literal(arg)
-
- if path.nil?
- path = @irb_context.irb_path
- elsif !File.exist?(path)
- source = SourceFinder.new(@irb_context).find_source(path)
-
- if source&.file_exist? && !source.binary_file?
- path = source.file
- end
- end
-
- unless File.exist?(path)
- puts "Can not find file: #{path}"
- return
- end
-
- if editor = (ENV['VISUAL'] || 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']"
- end
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/exit.rb b/lib/irb/command/exit.rb
deleted file mode 100644
index b4436f0343..0000000000
--- a/lib/irb/command/exit.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class Exit < Base
- category "IRB"
- description "Exit the current irb session."
-
- def execute(_arg)
- IRB.irb_exit
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/finish.rb b/lib/irb/command/finish.rb
deleted file mode 100644
index 3311a0e6e9..0000000000
--- a/lib/irb/command/finish.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Finish < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "finish #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/force_exit.rb b/lib/irb/command/force_exit.rb
deleted file mode 100644
index 14086aa849..0000000000
--- a/lib/irb/command/force_exit.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class ForceExit < Base
- category "IRB"
- description "Exit the current process."
-
- def execute(_arg)
- throw :IRB_EXIT, true
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/help.rb b/lib/irb/command/help.rb
deleted file mode 100644
index c2018f9b30..0000000000
--- a/lib/irb/command/help.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class Help < Base
- category "Help"
- description "List all available commands. Use `help <command>` to get information about a specific command."
-
- def execute(command_name)
- content =
- if command_name.empty?
- help_message
- else
- if command_class = Command.load_command(command_name)
- command_class.help_message || command_class.description
- else
- "Can't find command `#{command_name}`. Please check the command name and try again.\n\n"
- end
- end
- Pager.page_content(content)
- end
-
- private
-
- def help_message
- commands_info = IRB::Command.all_commands_info
- helper_methods_info = IRB::HelperMethod.all_helper_methods_info
- commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
- commands_grouped_by_categories["Helper methods"] = helper_methods_info
-
- if irb_context.with_debugger
- # Remove the original "Debugging" category
- commands_grouped_by_categories.delete("Debugging")
- end
-
- longest_cmd_name_length = commands_info.map { |c| c[:display_name].length }.max
-
- output = StringIO.new
-
- help_cmds = commands_grouped_by_categories.delete("Help")
- no_category_cmds = commands_grouped_by_categories.delete("No category")
- aliases = irb_context.instance_variable_get(:@user_aliases).map do |alias_name, target|
- { display_name: alias_name, description: "Alias for `#{target}`" }
- end
-
- # Display help commands first
- add_category_to_output("Help", help_cmds, output, longest_cmd_name_length)
-
- # Display the rest of the commands grouped by categories
- commands_grouped_by_categories.each do |category, cmds|
- add_category_to_output(category, cmds, output, longest_cmd_name_length)
- end
-
- # Display commands without a category
- if no_category_cmds
- add_category_to_output("No category", no_category_cmds, output, longest_cmd_name_length)
- end
-
- # Display aliases
- add_category_to_output("Aliases", aliases, output, longest_cmd_name_length)
-
- # Append the debugger help at the end
- if irb_context.with_debugger
- # Add "Debugging (from debug.gem)" category as title
- add_category_to_output("Debugging (from debug.gem)", [], output, longest_cmd_name_length)
- output.puts DEBUGGER__.help
- end
-
- output.string
- end
-
- def add_category_to_output(category, cmds, output, longest_cmd_name_length)
- output.puts Color.colorize(category, [:BOLD])
-
- cmds.each do |cmd|
- output.puts " #{cmd[:display_name].to_s.ljust(longest_cmd_name_length)} #{cmd[:description]}"
- end
-
- output.puts
- end
- end
- end
-end
diff --git a/lib/irb/command/history.rb b/lib/irb/command/history.rb
deleted file mode 100644
index 90f87f9102..0000000000
--- a/lib/irb/command/history.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require "stringio"
-
-require_relative "../pager"
-
-module IRB
- # :stopdoc:
-
- module Command
- class History < Base
- category "IRB"
- description "Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output."
-
- def execute(arg)
-
- if (match = arg&.match(/(-g|-G)\s+(?<grep>.+)\s*\n\z/))
- grep = Regexp.new(match[:grep])
- end
-
- formatted_inputs = irb_context.io.class::HISTORY.each_with_index.reverse_each.filter_map do |input, index|
- next if grep && !input.match?(grep)
-
- header = "#{index}: "
-
- first_line, *other_lines = input.split("\n")
- first_line = "#{header}#{first_line}"
-
- truncated_lines = other_lines.slice!(1..) # Show 1 additional line (2 total)
- other_lines << "..." if truncated_lines&.any?
-
- other_lines.map! do |line|
- " " * header.length + line
- end
-
- [first_line, *other_lines].join("\n") + "\n"
- end
-
- Pager.page_content(formatted_inputs.join)
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/info.rb b/lib/irb/command/info.rb
deleted file mode 100644
index d08ce00a32..0000000000
--- a/lib/irb/command/info.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Info < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "info #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/internal_helpers.rb b/lib/irb/command/internal_helpers.rb
deleted file mode 100644
index 249b5cdede..0000000000
--- a/lib/irb/command/internal_helpers.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- # Internal use only, for default command's backward compatibility.
- module RubyArgsExtractor # :nodoc:
- def unwrap_string_literal(str)
- return if str.empty?
-
- sexp = Ripper.sexp(str)
- if sexp && sexp.size == 2 && sexp.last&.first&.first == :string_literal
- @irb_context.workspace.binding.eval(str).to_s
- else
- str
- end
- end
-
- def ruby_args(arg)
- # Use throw and catch to handle arg that includes `;`
- # For example: "1, kw: (2; 3); 4" will be parsed to [[1], { kw: 3 }]
- catch(:EXTRACT_RUBY_ARGS) do
- @irb_context.workspace.binding.eval "IRB::Command.extract_ruby_args #{arg}"
- end || [[], {}]
- end
- end
- end
-end
diff --git a/lib/irb/command/irb_info.rb b/lib/irb/command/irb_info.rb
deleted file mode 100644
index 6d868de94c..0000000000
--- a/lib/irb/command/irb_info.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class IrbInfo < Base
- category "IRB"
- description "Show information about IRB."
-
- def execute(_arg)
- 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"
- rc_files = IRB.irbrc_files
- str += ".irbrc paths: #{rc_files.join(", ")}\n" if rc_files.any?
- 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
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/load.rb b/lib/irb/command/load.rb
deleted file mode 100644
index 1cd3f279d1..0000000000
--- a/lib/irb/command/load.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-#
-# load.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-require_relative "../ext/loader"
-
-module IRB
- # :stopdoc:
-
- module Command
- class LoaderCommand < Base
- include RubyArgsExtractor
- include IrbLoader
-
- def raise_cmd_argument_error
- raise CommandArgumentError.new("Please specify the file name.")
- end
- end
-
- class Load < LoaderCommand
- category "IRB"
- description "Load a Ruby file."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(file_name = nil, priv = nil)
- raise_cmd_argument_error unless file_name
- irb_load(file_name, priv)
- end
- end
-
- class Require < LoaderCommand
- category "IRB"
- description "Require a Ruby file."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(file_name = nil)
- raise_cmd_argument_error unless file_name
-
- rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
- return false if $".find{|f| f =~ rex}
-
- case file_name
- when /\.rb$/
- begin
- if irb_load(file_name)
- $".push file_name
- return true
- end
- rescue LoadError
- end
- when /\.(so|o|sl)$/
- return ruby_require(file_name)
- end
-
- begin
- irb_load(f = file_name + ".rb")
- $".push f
- return true
- rescue LoadError
- return ruby_require(file_name)
- end
- end
- end
-
- class Source < LoaderCommand
- category "IRB"
- description "Loads a given file in the current session."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(file_name = nil)
- raise_cmd_argument_error unless file_name
-
- source_file(file_name)
- end
- end
- end
- # :startdoc:
-end
diff --git a/lib/irb/command/ls.rb b/lib/irb/command/ls.rb
deleted file mode 100644
index cbd9998bc4..0000000000
--- a/lib/irb/command/ls.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-# frozen_string_literal: true
-
-require "reline"
-require "stringio"
-
-require_relative "../pager"
-require_relative "../color"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Ls < Base
- include RubyArgsExtractor
-
- category "Context"
- description "Show methods, constants, and variables."
-
- help_message <<~HELP_MESSAGE
- Usage: ls [obj] [-g [query]]
-
- -g [query] Filter the output with a query.
- HELP_MESSAGE
-
- def execute(arg)
- if match = arg.match(/\A(?<target>.+\s|)(-g|-G)\s+(?<grep>.+)$/)
- if match[:target].empty?
- use_main = true
- else
- obj = @irb_context.workspace.binding.eval(match[:target])
- end
- grep = Regexp.new(match[:grep])
- else
- args, kwargs = ruby_args(arg)
- use_main = args.empty?
- obj = args.first
- grep = kwargs[:grep]
- end
-
- if use_main
- obj = irb_context.workspace.main
- locals = irb_context.workspace.binding.local_variables
- end
-
- o = Output.new(grep: grep)
-
- klass = (obj.class == Class || obj.class == Module ? obj : obj.class)
-
- o.dump("constants", obj.constants) if obj.respond_to?(:constants)
- dump_methods(o, klass, obj)
- o.dump("instance variables", obj.instance_variables)
- o.dump("class variables", klass.class_variables)
- o.dump("locals", locals) if locals
- o.print_result
- 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.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
- end
-
- [mod, methods]
- end.compact
- end
-
- class Output
- MARGIN = " "
-
- 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)
- strs = strs.grep(@grep) if @grep
- strs = strs.sort
- return if strs.empty?
-
- # Attempt a single line
- @io.print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
- if fits_on_line?(strs, cols: strs.size, offset: "#{name}: ".length)
- @io.puts strs.join(MARGIN)
- return
- end
- @io.puts
-
- # Dump with the largest # of columns that fits on a line
- cols = strs.size
- until fits_on_line?(strs, cols: cols, offset: MARGIN.length) || cols == 1
- cols -= 1
- 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
- end
- end
-
- private
-
- def fits_on_line?(strs, cols:, offset: 0)
- width = col_widths(strs, cols: cols).sum + MARGIN.length * (cols - 1)
- width <= @line_width - offset
- end
-
- def col_widths(strs, cols:)
- cols.times.map do |col|
- (col...strs.size).step(cols).map do |i|
- strs[i].length
- end.max
- end
- end
-
- def screen_width
- Reline.get_screen_size.last
- rescue Errno::EINVAL # in `winsize': Invalid argument - <STDIN>
- 80
- end
- end
- private_constant :Output
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/measure.rb b/lib/irb/command/measure.rb
deleted file mode 100644
index f96be20de8..0000000000
--- a/lib/irb/command/measure.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-module IRB
- # :stopdoc:
-
- module Command
- class Measure < Base
- include RubyArgsExtractor
-
- category "Misc"
- description "`measure` enables the mode to measure processing time. `measure :off` disables it."
-
- def initialize(*args)
- super(*args)
- end
-
- def execute(arg)
- if arg&.match?(/^do$|^do[^\w]|^\{/)
- warn 'Configure IRB.conf[:MEASURE_PROC] to add custom measure methods.'
- return
- end
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(type = nil, arg = nil)
- # Please check IRB.init_config in lib/irb/init.rb that sets
- # IRB.conf[:MEASURE_PROC] to register default "measure" methods,
- # "measure :time" (abbreviated as "measure") and "measure :stackprof".
-
- case type
- when :off
- IRB.unset_measure_callback(arg)
- when :list
- IRB.conf[:MEASURE_CALLBACKS].each do |type_name, _, arg_val|
- puts "- #{type_name}" + (arg_val ? "(#{arg_val.inspect})" : '')
- end
- when :on
- added = IRB.set_measure_callback(arg)
- puts "#{added[0]} is added." if added
- else
- added = IRB.set_measure_callback(type, arg)
- puts "#{added[0]} is added." if added
- end
- nil
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/next.rb b/lib/irb/command/next.rb
deleted file mode 100644
index 3fc6b68d21..0000000000
--- a/lib/irb/command/next.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Next < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "next #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/pushws.rb b/lib/irb/command/pushws.rb
deleted file mode 100644
index b51928c650..0000000000
--- a/lib/irb/command/pushws.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-#
-# change-ws.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-require_relative "../ext/workspaces"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Workspaces < Base
- category "Workspace"
- description "Show workspaces."
-
- def execute(_arg)
- inspection_resuls = irb_context.instance_variable_get(:@workspace_stack).map do |ws|
- truncated_inspect(ws.main)
- end
-
- puts "[" + inspection_resuls.join(", ") + "]"
- end
-
- private
-
- def truncated_inspect(obj)
- obj_inspection = obj.inspect
-
- if obj_inspection.size > 20
- obj_inspection = obj_inspection[0, 19] + "...>"
- end
-
- obj_inspection
- end
- end
-
- class PushWorkspace < Workspaces
- category "Workspace"
- description "Push an object to the workspace stack."
-
- def execute(arg)
- if arg.empty?
- irb_context.push_workspace
- else
- obj = eval(arg, irb_context.workspace.binding)
- irb_context.push_workspace(obj)
- end
- super
- end
- end
-
- class PopWorkspace < Workspaces
- category "Workspace"
- description "Pop a workspace from the workspace stack."
-
- def execute(_arg)
- irb_context.pop_workspace
- super
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/show_doc.rb b/lib/irb/command/show_doc.rb
deleted file mode 100644
index 8a2188e4eb..0000000000
--- a/lib/irb/command/show_doc.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class ShowDoc < Base
- include RubyArgsExtractor
-
- category "Context"
- description "Look up documentation with RI."
-
- help_message <<~HELP_MESSAGE
- Usage: show_doc [name]
-
- When name is provided, IRB will look up the documentation for the given name.
- When no name is provided, a RI session will be started.
-
- Examples:
-
- show_doc
- show_doc Array
- show_doc Array#each
-
- HELP_MESSAGE
-
- def execute(arg)
- # Accept string literal for backward compatibility
- name = unwrap_string_literal(arg)
- 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 name.nil?
- Ri.interactive
- else
- begin
- Ri.display_name(name)
- rescue RDoc::RI::Error
- puts $!.message
- 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/command/show_source.rb b/lib/irb/command/show_source.rb
deleted file mode 100644
index f4c6f104a2..0000000000
--- a/lib/irb/command/show_source.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../source_finder"
-require_relative "../pager"
-require_relative "../color"
-
-module IRB
- module Command
- class ShowSource < Base
- include RubyArgsExtractor
-
- category "Context"
- description "Show the source code of a given method, class/module, or constant."
-
- help_message <<~HELP_MESSAGE
- Usage: show_source [target] [-s]
-
- -s Show the super method. You can stack it like `-ss` to show the super of the super, etc.
-
- Examples:
-
- show_source Foo
- show_source Foo#bar
- show_source Foo#bar -s
- show_source Foo.baz
- show_source Foo::BAR
- HELP_MESSAGE
-
- def execute(arg)
- # Accept string literal for backward compatibility
- str = unwrap_string_literal(arg)
- unless str.is_a?(String)
- puts "Error: Expected a string but got #{str.inspect}"
- return
- end
-
- str, esses = str.split(" -")
- super_level = esses ? esses.count("s") : 0
- source = SourceFinder.new(@irb_context).find_source(str, super_level)
-
- if source
- show_source(source)
- elsif super_level > 0
- puts "Error: Couldn't locate a super definition for #{str}"
- else
- puts "Error: Couldn't locate a definition for #{str}"
- end
- nil
- end
-
- private
-
- def show_source(source)
- if source.binary_file?
- content = "\n#{bold('Defined in binary file')}: #{source.file}\n\n"
- else
- code = source.colorized_content || 'Source not available'
- content = <<~CONTENT
-
- #{bold("From")}: #{source.file}:#{source.line}
-
- #{code.chomp}
-
- CONTENT
- end
- Pager.page_content(content)
- end
-
- def bold(str)
- Color.colorize(str, [:BOLD])
- end
- end
- end
-end
diff --git a/lib/irb/command/step.rb b/lib/irb/command/step.rb
deleted file mode 100644
index 29e5e35ac0..0000000000
--- a/lib/irb/command/step.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Step < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "step #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/subirb.rb b/lib/irb/command/subirb.rb
deleted file mode 100644
index 85af28c1a5..0000000000
--- a/lib/irb/command/subirb.rb
+++ /dev/null
@@ -1,123 +0,0 @@
-# frozen_string_literal: true
-#
-# multi.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-module IRB
- # :stopdoc:
-
- module Command
- class MultiIRBCommand < Base
- include RubyArgsExtractor
-
- 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)"
- description "Start a child IRB."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(*obj)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
- IRB.irb(nil, *obj)
- puts IRB.JobManager.inspect
- end
- end
-
- class Jobs < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "List of current sessions."
-
- def execute(_arg)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
- puts IRB.JobManager.inspect
- end
- end
-
- class Foreground < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "Switches to the session of the given number."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(key = nil)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
-
- raise CommandArgumentError.new("Please specify the id of target IRB job (listed in the `jobs` command).") unless key
- IRB.JobManager.switch(key)
- puts IRB.JobManager.inspect
- end
- end
-
- class Kill < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "Kills the session with the given number."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(*keys)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
- IRB.JobManager.kill(*keys)
- puts IRB.JobManager.inspect
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/whereami.rb b/lib/irb/command/whereami.rb
deleted file mode 100644
index c8439f1212..0000000000
--- a/lib/irb/command/whereami.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class Whereami < Base
- category "Context"
- description "Show the source code around binding.irb again."
-
- def execute(_arg)
- code = irb_context.workspace.code_around_binding
- if code
- puts code
- else
- puts "The current context doesn't have code."
- end
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index a3d89373c3..34640e17f9 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -1,6 +1,8 @@
-# frozen_string_literal: true
+# 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,74 +113,13 @@ module IRB
)
end
- def command_completions(preposing, target)
- if preposing.empty? && !target.empty?
- IRB::Command.command_names.select { _1.start_with?(target) }
- else
- []
- end
- 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 TypeCompletor < BaseCompletor # :nodoc:
- def initialize(context)
- @context = context
- end
-
- def inspect
- ReplTypeCompletor.info
- end
-
- def completion_candidates(preposing, target, _postposing, bind:)
- commands = command_completions(preposing, target)
- result = ReplTypeCompletor.analyze(preposing + target, binding: bind, filename: @context.irb_path)
- return commands unless result
-
- commands | result.completion_candidates.map { target + _1 }
- end
-
- def doc_namespace(preposing, matched, _postposing, bind:)
- result = ReplTypeCompletor.analyze(preposing + matched, binding: bind, filename: @context.irb_path)
- result&.doc_namespace('')
- 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
@@ -168,45 +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
- commands = command_completions(preposing || '', target)
- commands | 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}"
@@ -215,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
@@ -242,26 +205,26 @@ module IRB
end
when /^([^\}]*\})\.([^.]*)$/
- # Hash or Proc
+ # Proc or Hash
receiver = $1
message = $2
if doc_namespace
- ["Hash.#{message}", "Proc.#{message}"]
+ ["Proc.#{message}", "Hash.#{message}"]
else
- hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
- select_message(receiver, message, hash_candidates | proc_candidates)
+ hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
+ 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
@@ -276,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].*)::([^:.]*)$/
@@ -395,11 +358,19 @@ 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
rec_class = rec.is_a?(Module) ? rec : rec.class
- "#{rec_class.name}#{sep}#{candidates.find{ |i| i == message }}" rescue nil
+ "#{rec_class.name}#{sep}#{candidates.find{ |i| i == message }}"
else
select_message(receiver, message, candidates, sep)
end
@@ -417,19 +388,13 @@ module IRB
else
select_message(receiver, message, candidates.sort)
end
- when /^\s*$/
- # empty input
- if doc_namespace
- nil
- else
- []
- end
+
else
if doc_namespace
vars = (bind.local_variables | bind.eval_instance_variables).collect{|m| m.to_s}
perfect_match_var = vars.find{|m| m.to_s == input}
if perfect_match_var
- eval("#{perfect_match_var}.class.name", bind) rescue nil
+ eval("#{perfect_match_var}.class.name", bind)
else
candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
candidates |= ReservedWords
@@ -443,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_]/
@@ -457,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 5d2ff97328..91fbb2fcf1 100644
--- a/lib/irb/context.rb
+++ b/lib/irb/context.rb
@@ -1,9 +1,14 @@
-# frozen_string_literal: true
+# 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"
@@ -22,11 +27,10 @@ module IRB
# +other+:: uses this as InputMethod
def initialize(irb, workspace = nil, input_method = nil)
@irb = irb
- @workspace_stack = []
if workspace
- @workspace_stack << workspace
+ @workspace = workspace
else
- @workspace_stack << WorkSpace.new
+ @workspace = WorkSpace.new
end
@thread = Thread.current
@@ -62,7 +66,7 @@ module IRB
@io = nil
self.inspect_mode = IRB.conf[:INSPECT_MODE]
- self.use_tracer = IRB.conf[:USE_TRACER]
+ self.use_tracer = IRB.conf[:USE_TRACER] if IRB.conf[:USE_TRACER]
self.use_loader = IRB.conf[:USE_LOADER] if IRB.conf[:USE_LOADER]
self.eval_history = IRB.conf[:EVAL_HISTORY] if IRB.conf[:EVAL_HISTORY]
@@ -78,28 +82,28 @@ module IRB
else
@irb_name = IRB.conf[:IRB_NAME]+"#"+IRB.JobManager.n_jobs.to_s
end
- self.irb_path = "(" + @irb_name + ")"
+ @irb_path = "(" + @irb_name + ")"
case input_method
when nil
@io = nil
case use_multiline?
when nil
- if term_interactive? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
+ 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?
when nil
- if (defined?(ReadlineInputMethod) && term_interactive? &&
+ if (defined?(ReadlineInputMethod) && STDIN.tty? &&
IRB.conf[:PROMPT_MODE] != :INF_RUBY)
@io = ReadlineInputMethod.new
else
@@ -122,14 +126,16 @@ module IRB
when '-'
@io = FileInputMethod.new($stdin)
@irb_name = '-'
- self.irb_path = '-'
+ @irb_path = '-'
when String
@io = FileInputMethod.new(input_method)
@irb_name = File.basename(input_method)
- self.irb_path = input_method
+ @irb_path = input_method
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]
@@ -147,112 +153,18 @@ module IRB
@newline_before_multiline_output = true
end
- @user_aliases = IRB.conf[:COMMAND_ALIASES].dup
- @command_aliases = @user_aliases.merge(KEYWORD_ALIASES)
- end
-
- private def term_interactive?
- return true if ENV['TEST_IRB_FORCE_INTERACTIVE']
- STDIN.tty? && ENV['TERM'] != 'dumb'
- end
-
- # because all input will eventually be evaluated as Ruby code,
- # command names that conflict with Ruby keywords need special workaround
- # we can remove them once we implemented a better command system for IRB
- KEYWORD_ALIASES = {
- :break => :irb_break,
- :catch => :irb_catch,
- :next => :irb_next,
- }.freeze
-
- private_constant :KEYWORD_ALIASES
-
- def use_tracer=(val)
- require_relative "ext/tracer" if val
- IRB.conf[:USE_TRACER] = val
- end
-
- def eval_history=(val)
- self.class.remove_method(__method__)
- require_relative "ext/eval_history"
- __send__(__method__, val)
- end
-
- def use_loader=(val)
- self.class.remove_method(__method__)
- require_relative "ext/use-loader"
- __send__(__method__, val)
- 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
-
- private def build_type_completor
- if RUBY_ENGINE == 'truffleruby'
- # Avoid SyntaxError. truffleruby does not support endless method definition yet.
- warn 'TypeCompletor is not supported on TruffleRuby yet'
- return
- end
-
- begin
- require 'repl_type_completor'
- rescue LoadError => e
- warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}"
- return
- end
-
- ReplTypeCompletor.preload_rbs
- TypeCompletor.new(self)
- 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
-
- # Workspace in the current context.
- def workspace
- @workspace_stack.last
- end
-
- # Replace the current workspace with the given +workspace+.
- def replace_workspace(workspace)
- @workspace_stack.pop
- @workspace_stack.push(workspace)
+ @command_aliases = IRB.conf[:COMMAND_ALIASES]
end
# The top-level workspace, see WorkSpace#main
def main
- workspace.main
+ @workspace.main
end
# The toplevel workspace, see #home_workspace
attr_reader :workspace_home
+ # WorkSpace in the current context.
+ attr_accessor :workspace
# The current thread in this context.
attr_reader :thread
# The current input method.
@@ -273,27 +185,9 @@ module IRB
# Can be either name from <code>IRB.conf[:IRB_NAME]</code>, or the number of
# the current job set by JobManager, such as <code>irb#2</code>
attr_accessor :irb_name
-
- # Can be one of the following:
- # - the #irb_name surrounded by parenthesis
- # - the +input_method+ passed to Context.new
- # - the file path of the current IRB context in a binding.irb session
- attr_reader :irb_path
-
- # Sets @irb_path to the given +path+ as well as @eval_path
- # @eval_path is used for evaluating code in the context of IRB session
- # It's the same as irb_path, but with the IRB name postfix
- # This makes sure users can distinguish the methods defined in the IRB session
- # from the methods defined in the current file's context, especially with binding.irb
- def irb_path=(path)
- @irb_path = path
-
- if File.exist?(path)
- @eval_path = "#{path}(#{IRB.conf[:IRB_NAME]})"
- else
- @eval_path = path
- end
- end
+ # Can be either the #irb_name surrounded by parenthesis, or the
+ # +input_method+ passed to Context.new
+ attr_accessor :irb_path
# Whether multiline editor mode is enabled or not.
#
@@ -314,29 +208,18 @@ module IRB
attr_reader :prompt_mode
# Standard IRB prompt.
#
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # See IRB@Customizing+the+IRB+Prompt for more information.
attr_accessor :prompt_i
# IRB prompt for continuated strings.
#
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # See IRB@Customizing+the+IRB+Prompt for more information.
attr_accessor :prompt_s
# IRB prompt for continuated statement. (e.g. immediately after an +if+)
#
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # 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=
#
@@ -444,13 +327,13 @@ module IRB
# The default value is 16.
#
# Can also be set using the +--back-trace-limit+ command line option.
+ #
+ # See IRB@Command+line+options for more command line options.
attr_accessor :back_trace_limit
# 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
@@ -494,7 +377,9 @@ module IRB
# StdioInputMethod or RelineInputMethod or ReadlineInputMethod, see #io
# for more information.
def prompting?
- verbose? || @io.prompting?
+ verbose? || (STDIN.tty? && @io.kind_of?(StdioInputMethod) ||
+ @io.kind_of?(RelineInputMethod) ||
+ (defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod)))
end
# The return value of the last statement evaluated.
@@ -504,18 +389,19 @@ module IRB
# to #last_value.
def set_last_value(value)
@last_value = value
- workspace.local_variable_set :_, value
+ @workspace.local_variable_set :_, value
end
# Sets the +mode+ of the prompt in this context.
#
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # See IRB@Customizing+the+IRB+Prompt for more information.
def prompt_mode=(mode)
@prompt_mode = mode
pconf = IRB.conf[:PROMPT][mode]
@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)
@@ -547,6 +433,8 @@ module IRB
#
# Can also be set using the +--inspect+ and +--noinspect+ command line
# options.
+ #
+ # See IRB@Command+line+options for more command line options.
def inspect_mode=(opt)
if i = Inspector::INSPECTORS[opt]
@@ -590,55 +478,42 @@ module IRB
@inspect_mode
end
- def evaluate(statement, line_no) # :nodoc:
+ def evaluate(line, line_no, exception: nil) # :nodoc:
@line_no = line_no
-
- case statement
- when Statement::EmptyInput
- return
- when Statement::Expression
- result = evaluate_expression(statement.code, line_no)
- set_last_value(result)
- when Statement::Command
- statement.command_class.execute(self, statement.arg)
- set_last_value(nil)
+ if exception
+ line_no -= 1
+ line = "begin ::Kernel.raise _; rescue _.class\n#{line}\n""end"
+ @workspace.local_variable_set(:_, exception)
end
- nil
- end
-
- def from_binding?
- @irb.from_binding
- end
-
- def evaluate_expression(code, line_no) # :nodoc:
- result = nil
- 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(code, @eval_path, line_no)
- end
- IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) do |chain, item|
- _name, callback, arg = item
- proc do
- callback.(self, code, line_no, arg) do
- chain.call
- end
- end
- end.call
- else
- result = workspace.evaluate(code, @eval_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
- result
+
+ set_last_value(@workspace.evaluate(self, line, irb_path, line_no))
end
def inspect_last_value # :nodoc:
@inspect_method.inspect_value(@last_value)
end
+ alias __exit__ exit
+ # Exits the current session, see IRB.irb_exit
+ def exit(ret = 0)
+ IRB.irb_exit(@irb, ret)
+ rescue UncaughtThrowError
+ super
+ end
+
NOPRINTING_IVARS = ["@last_value"] # :nodoc:
NO_INSPECTING_IVARS = ["@irb", "@io"] # :nodoc:
IDNAME_IVARS = ["@prompt_mode"] # :nodoc:
@@ -669,5 +544,17 @@ module IRB
def local_variables # :nodoc:
workspace.binding.local_variables
end
+
+ # Return true if it's aliased from the argument and it's not an identifier.
+ def symbol_alias?(command)
+ return nil if command.match?(/\A\w+\z/)
+ command_aliases.key?(command.to_sym)
+ end
+
+ # Return true if the command supports transforming args
+ def transform_args?(command)
+ command = command_aliases.fetch(command.to_sym, command)
+ ExtendCommandBundle.load_command(command)&.respond_to?(:transform_args)
+ end
end
end
diff --git a/lib/irb/debug.rb b/lib/irb/debug.rb
deleted file mode 100644
index 1ec2335a8e..0000000000
--- a/lib/irb/debug.rb
+++ /dev/null
@@ -1,130 +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
-
- if !@output_modifier_defined && !DEBUGGER__::CONFIG[:no_hint]
- irb_output_modifier_proc = Reline.output_modifier_proc
-
- Reline.output_modifier_proc = proc do |output, complete:|
- unless output.strip.empty?
- cmd = output.split(/\s/, 2).first
-
- if !complete && DEBUGGER__.commands.key?(cmd)
- output = output.sub(/\n$/, " # debug command\n")
- end
- end
-
- irb_output_modifier_proc.call(output, complete: complete)
- end
-
- @output_modifier_defined = true
- 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/default_commands.rb b/lib/irb/default_commands.rb
deleted file mode 100644
index 1bbc68efa7..0000000000
--- a/lib/irb/default_commands.rb
+++ /dev/null
@@ -1,260 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "command"
-require_relative "command/internal_helpers"
-require_relative "command/context"
-require_relative "command/exit"
-require_relative "command/force_exit"
-require_relative "command/chws"
-require_relative "command/pushws"
-require_relative "command/subirb"
-require_relative "command/load"
-require_relative "command/debug"
-require_relative "command/edit"
-require_relative "command/break"
-require_relative "command/catch"
-require_relative "command/next"
-require_relative "command/delete"
-require_relative "command/step"
-require_relative "command/continue"
-require_relative "command/finish"
-require_relative "command/backtrace"
-require_relative "command/info"
-require_relative "command/help"
-require_relative "command/show_doc"
-require_relative "command/irb_info"
-require_relative "command/ls"
-require_relative "command/measure"
-require_relative "command/show_source"
-require_relative "command/whereami"
-require_relative "command/history"
-
-module IRB
- module Command
- NO_OVERRIDE = 0
- OVERRIDE_PRIVATE_ONLY = 0x01
- OVERRIDE_ALL = 0x02
-
- class << self
- # This API is for IRB's internal use only and may change at any time.
- # Please do NOT use it.
- def _register_with_aliases(name, command_class, *aliases)
- @commands[name.to_sym] = [command_class, aliases]
- end
-
- def all_commands_info
- user_aliases = IRB.CurrentContext.command_aliases.each_with_object({}) do |(alias_name, target), result|
- result[target] ||= []
- result[target] << alias_name
- end
-
- commands.map do |command_name, (command_class, aliases)|
- aliases = aliases.map { |a| a.first }
-
- if additional_aliases = user_aliases[command_name]
- aliases += additional_aliases
- end
-
- display_name = aliases.shift || command_name
- {
- display_name: display_name,
- description: command_class.description,
- category: command_class.category
- }
- end
- end
-
- def command_override_policies
- @@command_override_policies ||= commands.flat_map do |cmd_name, (cmd_class, aliases)|
- [[cmd_name, OVERRIDE_ALL]] + aliases
- end.to_h
- end
-
- def execute_as_command?(name, public_method:, private_method:)
- case command_override_policies[name]
- when OVERRIDE_ALL
- true
- when OVERRIDE_PRIVATE_ONLY
- !public_method
- when NO_OVERRIDE
- !public_method && !private_method
- end
- end
-
- def command_names
- command_override_policies.keys.map(&:to_s)
- end
-
- # Convert a command name to its implementation class if such command exists
- def load_command(command)
- command = command.to_sym
- commands.each do |command_name, (command_class, aliases)|
- if command_name == command || aliases.any? { |alias_name, _| alias_name == command }
- return command_class
- end
- end
- nil
- end
- end
-
- _register_with_aliases(:irb_context, Command::Context,
- [:context, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_exit, Command::Exit,
- [:exit, OVERRIDE_PRIVATE_ONLY],
- [:quit, OVERRIDE_PRIVATE_ONLY],
- [:irb_quit, OVERRIDE_PRIVATE_ONLY]
- )
-
- _register_with_aliases(:irb_exit!, Command::ForceExit,
- [:exit!, OVERRIDE_PRIVATE_ONLY]
- )
-
- _register_with_aliases(:irb_current_working_workspace, Command::CurrentWorkingWorkspace,
- [:cwws, NO_OVERRIDE],
- [:pwws, NO_OVERRIDE],
- [:irb_print_working_workspace, OVERRIDE_ALL],
- [:irb_cwws, OVERRIDE_ALL],
- [:irb_pwws, OVERRIDE_ALL],
- [:irb_current_working_binding, OVERRIDE_ALL],
- [:irb_print_working_binding, OVERRIDE_ALL],
- [:irb_cwb, OVERRIDE_ALL],
- [:irb_pwb, OVERRIDE_ALL],
- )
-
- _register_with_aliases(:irb_change_workspace, Command::ChangeWorkspace,
- [:chws, NO_OVERRIDE],
- [:cws, NO_OVERRIDE],
- [:irb_chws, OVERRIDE_ALL],
- [:irb_cws, OVERRIDE_ALL],
- [:irb_change_binding, OVERRIDE_ALL],
- [:irb_cb, OVERRIDE_ALL],
- [:cb, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_workspaces, Command::Workspaces,
- [:workspaces, NO_OVERRIDE],
- [:irb_bindings, OVERRIDE_ALL],
- [:bindings, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_push_workspace, Command::PushWorkspace,
- [:pushws, NO_OVERRIDE],
- [:irb_pushws, OVERRIDE_ALL],
- [:irb_push_binding, OVERRIDE_ALL],
- [:irb_pushb, OVERRIDE_ALL],
- [:pushb, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_pop_workspace, Command::PopWorkspace,
- [:popws, NO_OVERRIDE],
- [:irb_popws, OVERRIDE_ALL],
- [:irb_pop_binding, OVERRIDE_ALL],
- [:irb_popb, OVERRIDE_ALL],
- [:popb, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_load, Command::Load)
- _register_with_aliases(:irb_require, Command::Require)
- _register_with_aliases(:irb_source, Command::Source,
- [:source, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb, Command::IrbCommand)
- _register_with_aliases(:irb_jobs, Command::Jobs,
- [:jobs, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_fg, Command::Foreground,
- [:fg, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_kill, Command::Kill,
- [:kill, OVERRIDE_PRIVATE_ONLY]
- )
-
- _register_with_aliases(:irb_debug, Command::Debug,
- [:debug, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_edit, Command::Edit,
- [:edit, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_break, Command::Break)
- _register_with_aliases(:irb_catch, Command::Catch)
- _register_with_aliases(:irb_next, Command::Next)
- _register_with_aliases(:irb_delete, Command::Delete,
- [:delete, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_step, Command::Step,
- [:step, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_continue, Command::Continue,
- [:continue, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_finish, Command::Finish,
- [:finish, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_backtrace, Command::Backtrace,
- [:backtrace, NO_OVERRIDE],
- [:bt, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_debug_info, Command::Info,
- [:info, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_help, Command::Help,
- [:help, NO_OVERRIDE],
- [:show_cmds, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_show_doc, Command::ShowDoc,
- [:show_doc, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_info, Command::IrbInfo)
-
- _register_with_aliases(:irb_ls, Command::Ls,
- [:ls, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_measure, Command::Measure,
- [:measure, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_show_source, Command::ShowSource,
- [:show_source, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_whereami, Command::Whereami,
- [:whereami, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_history, Command::History,
- [:history, NO_OVERRIDE],
- [:hist, NO_OVERRIDE]
- )
- end
-
- ExtendCommand = Command
-
- # For backward compatibility, we need to keep this module:
- # - As a container of helper methods
- # - As a place to register commands with the deprecated def_extend_command method
- module ExtendCommandBundle
- # For backward compatibility
- NO_OVERRIDE = Command::NO_OVERRIDE
- OVERRIDE_PRIVATE_ONLY = Command::OVERRIDE_PRIVATE_ONLY
- OVERRIDE_ALL = Command::OVERRIDE_ALL
-
- # Deprecated. Doesn't have any effect.
- @EXTEND_COMMANDS = []
-
- # Drepcated. Use Command.regiser instead.
- def self.def_extend_command(cmd_name, cmd_class, _, *aliases)
- Command._register_with_aliases(cmd_name, cmd_class, *aliases)
- Command.class_variable_set(:@@command_override_policies, nil)
- 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 60e8afe31f..4c57e44eab 100644
--- a/lib/irb/ext/change-ws.rb
+++ b/lib/irb/ext/change-ws.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# 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
@@ -12,7 +18,7 @@ module IRB # :nodoc:
if defined? @home_workspace
@home_workspace
else
- @home_workspace = workspace
+ @home_workspace = @workspace
end
end
@@ -25,13 +31,15 @@ module IRB # :nodoc:
# See IRB::WorkSpace.new for more information.
def change_workspace(*_main)
if _main.empty?
- replace_workspace(home_workspace)
+ @workspace = home_workspace
return main
end
- workspace = WorkSpace.new(_main[0])
- replace_workspace(workspace)
- workspace.load_helper_methods_to_main
+ @workspace = WorkSpace.new(_main[0])
+
+ if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
+ main.extend ExtendCommandBundle
+ end
end
end
end
diff --git a/lib/irb/ext/eval_history.rb b/lib/irb/ext/eval_history.rb
deleted file mode 100644
index 6c21ff00ee..0000000000
--- a/lib/irb/ext/eval_history.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-# frozen_string_literal: true
-#
-# 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 df5aaa8e5a..af028996e7 100644
--- a/lib/irb/ext/loader.rb
+++ b/lib/irb/ext/loader.rb
@@ -1,8 +1,15 @@
-# frozen_string_literal: true
+# 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
@@ -98,13 +126,13 @@ module IRB # :nodoc:
def old # :nodoc:
back_io = @io
- back_path = irb_path
+ back_path = @irb_path
back_name = @irb_name
back_scanner = @irb.scanner
begin
@io = FileInputMethod.new(path)
@irb_name = File.basename(path)
- self.irb_path = path
+ @irb_path = path
@irb.signal_status(:IN_LOAD) do
if back_io.kind_of?(FileInputMethod)
@irb.eval_input
@@ -119,7 +147,7 @@ module IRB # :nodoc:
ensure
@io = back_io
@irb_name = back_name
- self.irb_path = back_path
+ @irb_path = back_path
@irb.scanner = back_scanner
end
end
diff --git a/lib/irb/ext/multi-irb.rb b/lib/irb/ext/multi-irb.rb
index 9f234f0cdc..e57d43a569 100644
--- a/lib/irb/ext/multi-irb.rb
+++ b/lib/irb/ext/multi-irb.rb
@@ -1,11 +1,17 @@
-# frozen_string_literal: true
+# 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 # :nodoc:
+ class JobManager
# Creates a new JobManager object
def initialize
@@ -166,12 +172,12 @@ module IRB
@JobManager = JobManager.new
# The current JobManager in the session
- def IRB.JobManager # :nodoc:
+ def IRB.JobManager
@JobManager
end
# The current Context in this session
- def IRB.CurrentContext # :nodoc:
+ def IRB.CurrentContext
IRB.JobManager.irb(Thread.current).context
end
@@ -179,7 +185,7 @@ module IRB
#
# The optional +file+ argument is given to Context.new, along with the
# workspace created with the remaining arguments, see WorkSpace.new
- def IRB.irb(file = nil, *main) # :nodoc:
+ def IRB.irb(file = nil, *main)
workspace = WorkSpace.new(*main)
parent_thread = Thread.current
Thread.start do
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 fd6daa88ae..67ac4bb965 100644
--- a/lib/irb/ext/tracer.rb
+++ b/lib/irb/ext/tracer.rb
@@ -1,39 +1,84 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/lib/tracer.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-# Loading the gem "tracer" will cause it to extend IRB commands with:
-# https://github.com/ruby/tracer/blob/v0.2.2/lib/tracer/irb.rb
+# --
+#
+#
+#
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
+ end
+ end
+ end
return # This is about to disable loading below
end
module IRB
- class CallTracer < ::CallTracer
- IRB_DIR = File.expand_path('../..', __dir__)
- def skip?(tp)
- super || tp.path.match?(IRB_DIR) || tp.path.match?('<internal:prelude>')
+ # initialize tracing function
+ def IRB.initialize_tracer
+ Tracer.verbose = false
+ Tracer.add_filter {
+ |event, file, line, id, binding, *rests|
+ /^#{Regexp.quote(@CONF[:IRB_LIB_PATH])}/ !~ file and
+ File::basename(file) != "irb.rb"
+ }
+ end
+
+ class Context
+ # Whether Tracer is used when evaluating statements in this context.
+ #
+ # See +lib/tracer.rb+ for more information.
+ attr_reader :use_tracer
+ alias use_tracer? use_tracer
+
+ # Sets whether or not to use the Tracer library when evaluating statements
+ # in this context.
+ #
+ # See +lib/tracer.rb+ for more information.
+ def use_tracer=(opt)
+ if opt
+ Tracer.set_get_line_procs(@irb_path) {
+ |line_no, *rests|
+ @io.line(line_no)
+ }
+ elsif !opt && @use_tracer
+ Tracer.off
+ end
+ @use_tracer=opt
end
end
+
class WorkSpace
alias __evaluate__ evaluate
# Evaluate the context of this workspace and use the Tracer library to
# output the exact lines of code are being executed in chronological order.
#
- # See https://github.com/ruby/tracer for more information.
- def evaluate(statements, file = __FILE__, line = __LINE__)
- if IRB.conf[:USE_TRACER] == true
- CallTracer.new(colorize: Color.colorable?).start do
- __evaluate__(statements, file, line)
+ # See +lib/tracer.rb+ for more information.
+ def evaluate(context, statements, file = nil, line = nil)
+ if context.use_tracer? && file != nil && line != nil
+ Tracer.on
+ begin
+ __evaluate__(context, statements, file, line)
+ ensure
+ Tracer.off
end
else
- __evaluate__(statements, file, line)
+ __evaluate__(context, statements, file || __FILE__, line || __LINE__)
end
end
end
+
+ IRB.initialize_tracer
end
diff --git a/lib/irb/ext/use-loader.rb b/lib/irb/ext/use-loader.rb
index c8a3ea1fe8..1897bc89e0 100644
--- a/lib/irb/ext/use-loader.rb
+++ b/lib/irb/ext/use-loader.rb
@@ -1,10 +1,16 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# use-loader.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
-require_relative "../command/load"
+require_relative "../cmd/load"
require_relative "loader"
class Object
@@ -17,12 +23,12 @@ module IRB
remove_method :irb_load if method_defined?(:irb_load)
# Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
def irb_load(*opts, &b)
- Command::Load.execute(irb_context, *opts, &b)
+ ExtendCommand::Load.execute(irb_context, *opts, &b)
end
remove_method :irb_require if method_defined?(:irb_require)
# Loads the given file similarly to Kernel#require
def irb_require(*opts, &b)
- Command::Require.execute(irb_context, *opts, &b)
+ ExtendCommand::Require.execute(irb_context, *opts, &b)
end
end
@@ -49,12 +55,14 @@ module IRB
if IRB.conf[:USE_LOADER] != opt
IRB.conf[:USE_LOADER] = opt
if opt
- (class<<workspace.main;self;end).instance_eval {
+ if !$".include?("irb/cmd/load")
+ end
+ (class<<@workspace.main;self;end).instance_eval {
alias_method :load, :irb_load
alias_method :require, :irb_require
}
else
- (class<<workspace.main;self;end).instance_eval {
+ (class<<@workspace.main;self;end).instance_eval {
alias_method :load, :__original__load__IRB_use_loader__
alias_method :require, :__original__require__IRB_use_loader__
}
diff --git a/lib/irb/ext/workspaces.rb b/lib/irb/ext/workspaces.rb
index da09faa83e..730b58e64d 100644
--- a/lib/irb/ext/workspaces.rb
+++ b/lib/irb/ext/workspaces.rb
@@ -1,11 +1,32 @@
-# frozen_string_literal: true
+# 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
+
+ # Size of the current WorkSpace stack
+ def irb_level
+ workspace_stack.size
+ end
+
+ # WorkSpaces in the current stack
+ def workspaces
+ if defined? @workspaces
+ @workspaces
+ else
+ @workspaces = []
+ end
+ end
+
# Creates a new workspace with the given object or binding, and appends it
# onto the current #workspaces stack.
#
@@ -13,15 +34,20 @@ module IRB # :nodoc:
# information.
def push_workspace(*_main)
if _main.empty?
- if @workspace_stack.size > 1
- # swap the top two workspaces
- previous_workspace, current_workspace = @workspace_stack.pop(2)
- @workspace_stack.push current_workspace, previous_workspace
+ if workspaces.empty?
+ print "No other workspace\n"
+ return nil
end
- else
- new_workspace = WorkSpace.new(workspace.binding, _main[0])
- @workspace_stack.push new_workspace
- new_workspace.load_helper_methods_to_main
+ ws = workspaces.pop
+ workspaces.push @workspace
+ @workspace = ws
+ return workspaces
+ end
+
+ workspaces.push @workspace
+ @workspace = WorkSpace.new(@workspace.binding, _main[0])
+ if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
+ main.extend ExtendCommandBundle
end
end
@@ -30,7 +56,11 @@ module IRB # :nodoc:
#
# Also, see #push_workspace.
def pop_workspace
- @workspace_stack.pop if @workspace_stack.size > 1
+ if workspaces.empty?
+ print "workspace stack empty\n"
+ return
+ end
+ @workspace = workspaces.pop
end
end
end
diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb
new file mode 100644
index 0000000000..d0829a06c4
--- /dev/null
+++ b/lib/irb/extend-command.rb
@@ -0,0 +1,433 @@
+# 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
+ EXCB = ExtendCommandBundle # :nodoc:
+
+ # See #install_alias_method.
+ NO_OVERRIDE = 0
+ # See #install_alias_method.
+ OVERRIDE_PRIVATE_ONLY = 0x01
+ # See #install_alias_method.
+ OVERRIDE_ALL = 0x02
+
+ # Quits the current irb context
+ #
+ # +ret+ is the optional signal or message to send to Context#exit
+ #
+ # Same as <code>IRB.CurrentContext.exit</code>.
+ def irb_exit(ret = 0)
+ irb_context.exit(ret)
+ end
+
+ # Displays current configuration.
+ #
+ # Modifying the configuration is achieved by sending a message to IRB.conf.
+ def irb_context
+ IRB.CurrentContext
+ end
+
+ @ALIASES = [
+ [:context, :irb_context, NO_OVERRIDE],
+ [:conf, :irb_context, NO_OVERRIDE],
+ [:irb_quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
+ [:exit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
+ [:quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
+ ]
+
+
+ @EXTEND_COMMANDS = [
+ [
+ :irb_current_working_workspace, :CurrentWorkingWorkspace, "cmd/chws",
+ [:cwws, NO_OVERRIDE],
+ [:pwws, NO_OVERRIDE],
+ [:irb_print_working_workspace, OVERRIDE_ALL],
+ [:irb_cwws, OVERRIDE_ALL],
+ [:irb_pwws, OVERRIDE_ALL],
+ [:irb_current_working_binding, OVERRIDE_ALL],
+ [:irb_print_working_binding, OVERRIDE_ALL],
+ [:irb_cwb, OVERRIDE_ALL],
+ [:irb_pwb, OVERRIDE_ALL],
+ ],
+ [
+ :irb_change_workspace, :ChangeWorkspace, "cmd/chws",
+ [:chws, NO_OVERRIDE],
+ [:cws, NO_OVERRIDE],
+ [:irb_chws, OVERRIDE_ALL],
+ [:irb_cws, OVERRIDE_ALL],
+ [:irb_change_binding, OVERRIDE_ALL],
+ [:irb_cb, OVERRIDE_ALL],
+ [:cb, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_workspaces, :Workspaces, "cmd/pushws",
+ [:workspaces, NO_OVERRIDE],
+ [:irb_bindings, OVERRIDE_ALL],
+ [:bindings, NO_OVERRIDE],
+ ],
+ [
+ :irb_push_workspace, :PushWorkspace, "cmd/pushws",
+ [:pushws, NO_OVERRIDE],
+ [:irb_pushws, OVERRIDE_ALL],
+ [:irb_push_binding, OVERRIDE_ALL],
+ [:irb_pushb, OVERRIDE_ALL],
+ [:pushb, NO_OVERRIDE],
+ ],
+ [
+ :irb_pop_workspace, :PopWorkspace, "cmd/pushws",
+ [:popws, NO_OVERRIDE],
+ [:irb_popws, OVERRIDE_ALL],
+ [:irb_pop_binding, OVERRIDE_ALL],
+ [:irb_popb, OVERRIDE_ALL],
+ [:popb, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_load, :Load, "cmd/load"],
+ [
+ :irb_require, :Require, "cmd/load"],
+ [
+ :irb_source, :Source, "cmd/load",
+ [:source, NO_OVERRIDE],
+ ],
+
+ [
+ :irb, :IrbCommand, "cmd/subirb"],
+ [
+ :irb_jobs, :Jobs, "cmd/subirb",
+ [:jobs, NO_OVERRIDE],
+ ],
+ [
+ :irb_fg, :Foreground, "cmd/subirb",
+ [:fg, NO_OVERRIDE],
+ ],
+ [
+ :irb_kill, :Kill, "cmd/subirb",
+ [:kill, OVERRIDE_PRIVATE_ONLY],
+ ],
+
+ [
+ :irb_debug, :Debug, "cmd/debug",
+ [:debug, NO_OVERRIDE],
+ ],
+ [
+ :irb_edit, :Edit, "cmd/edit",
+ [:edit, NO_OVERRIDE],
+ ],
+ [
+ :irb_break, :Break, "cmd/break",
+ ],
+ [
+ :irb_catch, :Catch, "cmd/catch",
+ ],
+ [
+ :irb_next, :Next, "cmd/next"
+ ],
+ [
+ :irb_delete, :Delete, "cmd/delete",
+ [:delete, NO_OVERRIDE],
+ ],
+ [
+ :irb_step, :Step, "cmd/step",
+ [:step, NO_OVERRIDE],
+ ],
+ [
+ :irb_continue, :Continue, "cmd/continue",
+ [:continue, NO_OVERRIDE],
+ ],
+ [
+ :irb_finish, :Finish, "cmd/finish",
+ [:finish, NO_OVERRIDE],
+ ],
+ [
+ :irb_backtrace, :Backtrace, "cmd/backtrace",
+ [:backtrace, NO_OVERRIDE],
+ [:bt, NO_OVERRIDE],
+ ],
+ [
+ :irb_debug_info, :Info, "cmd/info",
+ [:info, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_help, :Help, "cmd/help",
+ [:show_doc, NO_OVERRIDE],
+ [:help, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_info, :IrbInfo, "cmd/irb_info"
+ ],
+
+ [
+ :irb_ls, :Ls, "cmd/ls",
+ [:ls, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_measure, :Measure, "cmd/measure",
+ [:measure, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_show_source, :ShowSource, "cmd/show_source",
+ [:show_source, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_whereami, :Whereami, "cmd/whereami",
+ [:whereami, NO_OVERRIDE],
+ ],
+ [
+ :irb_show_cmds, :ShowCmds, "cmd/show_cmds",
+ [:show_cmds, NO_OVERRIDE],
+ ]
+ ]
+
+
+ @@commands = []
+
+ def self.all_commands_info
+ return @@commands unless @@commands.empty?
+ user_aliases = IRB.CurrentContext.command_aliases.each_with_object({}) do |(alias_name, target), result|
+ result[target] ||= []
+ result[target] << alias_name
+ end
+
+ @EXTEND_COMMANDS.each do |cmd_name, cmd_class, load_file, *aliases|
+ if !defined?(ExtendCommand) || !ExtendCommand.const_defined?(cmd_class, false)
+ require_relative load_file
+ end
+
+ klass = ExtendCommand.const_get(cmd_class, false)
+ aliases = aliases.map { |a| a.first }
+
+ if additional_aliases = user_aliases[cmd_name]
+ aliases += additional_aliases
+ end
+
+ display_name = aliases.shift || cmd_name
+ @@commands << { display_name: display_name, description: klass.description, category: klass.category }
+ end
+
+ @@commands
+ end
+
+ # Convert a command name to its implementation class if such command exists
+ def self.load_command(command)
+ command = command.to_sym
+ @EXTEND_COMMANDS.each do |cmd_name, cmd_class, load_file, *aliases|
+ next if cmd_name != command && aliases.all? { |alias_name, _| alias_name != command }
+
+ if !defined?(ExtendCommand) || !ExtendCommand.const_defined?(cmd_class, false)
+ require_relative load_file
+ end
+ return ExtendCommand.const_get(cmd_class, false)
+ end
+ nil
+ end
+
+ # Installs the default irb commands.
+ def self.install_extend_commands
+ for args in @EXTEND_COMMANDS
+ def_extend_command(*args)
+ end
+ end
+
+ # Evaluate the given +cmd_name+ on the given +cmd_class+ Class.
+ #
+ # Will also define any given +aliases+ for the method.
+ #
+ # The optional +load_file+ parameter will be required within the method
+ # definition.
+ def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
+ case cmd_class
+ when Symbol
+ cmd_class = cmd_class.id2name
+ when String
+ when Class
+ cmd_class = cmd_class.name
+ end
+
+ 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]
+ end
+ end
+
+ # Installs alias methods for the default irb commands, see
+ # ::install_extend_commands.
+ def install_alias_method(to, from, override = NO_OVERRIDE)
+ to = to.id2name unless to.kind_of?(String)
+ from = from.id2name unless from.kind_of?(String)
+
+ if override == OVERRIDE_ALL or
+ (override == OVERRIDE_PRIVATE_ONLY) && !respond_to?(to) or
+ (override == NO_OVERRIDE) && !respond_to?(to, true)
+ target = self
+ (class << self; self; end).instance_eval{
+ if target.respond_to?(to, true) &&
+ !target.respond_to?(EXCB.irb_original_method_name(to), true)
+ alias_method(EXCB.irb_original_method_name(to), to)
+ end
+ alias_method to, from
+ }
+ else
+ Kernel.print "irb: warn: can't alias #{to} from #{from}.\n"
+ end
+ end
+
+ def self.irb_original_method_name(method_name) # :nodoc:
+ "irb_" + method_name + "_org"
+ end
+
+ # Installs alias methods for the default irb commands on the given object
+ # using #install_alias_method.
+ def self.extend_object(obj)
+ unless (class << obj; ancestors; end).include?(EXCB)
+ super
+ for ali, com, flg in @ALIASES
+ obj.install_alias_method(ali, com, flg)
+ end
+ end
+ end
+
+ install_extend_commands
+ end
+
+ # Extends methods for the Context module
+ module ContextExtender
+ CE = ContextExtender # :nodoc:
+
+ @EXTEND_COMMANDS = [
+ [: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:
+ #
+ # 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)
+ end
+ end
+
+ # Evaluate the given +command+ from the given +load_file+ on the Context
+ # module.
+ #
+ # Will also define any given +aliases+ for the method.
+ def self.def_extend_command(cmd_name, load_file, *aliases)
+ line = __LINE__; Context.module_eval %[
+ def #{cmd_name}(*opts, &b)
+ Context.module_eval {remove_method(:#{cmd_name})}
+ require_relative "#{load_file}"
+ __send__ :#{cmd_name}, *opts, &b
+ end
+ for ali in aliases
+ alias_method ali, cmd_name
+ end
+ ], __FILE__, line
+ end
+
+ 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 4b697c8719..de54a98f1b 100644
--- a/lib/irb/frame.rb
+++ b/lib/irb/frame.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# 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 a24bc10a15..3eeaf841b0 100644
--- a/lib/irb/help.rb
+++ b/lib/irb/help.rb
@@ -1,16 +1,24 @@
-# frozen_string_literal: true
+# 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.
- def IRB.print_usage # :nodoc:
+ # Outputs the irb help message, see IRB@Command+line+options.
+ def IRB.print_usage
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/helper_method.rb b/lib/irb/helper_method.rb
deleted file mode 100644
index f1f6fff915..0000000000
--- a/lib/irb/helper_method.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative "helper_method/base"
-
-module IRB
- module HelperMethod
- @helper_methods = {}
-
- class << self
- attr_reader :helper_methods
-
- def register(name, helper_class)
- @helper_methods[name] = helper_class
-
- if defined?(HelpersContainer)
- HelpersContainer.install_helper_methods
- end
- end
-
- def all_helper_methods_info
- @helper_methods.map do |name, helper_class|
- { display_name: name, description: helper_class.description }
- end
- end
- end
-
- # Default helper_methods
- require_relative "helper_method/conf"
- register(:conf, HelperMethod::Conf)
- end
-end
diff --git a/lib/irb/helper_method/base.rb b/lib/irb/helper_method/base.rb
deleted file mode 100644
index a68001ed28..0000000000
--- a/lib/irb/helper_method/base.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require "singleton"
-
-module IRB
- module HelperMethod
- class Base
- include Singleton
-
- class << self
- def description(description = nil)
- @description = description if description
- @description
- end
- end
- end
- end
-end
diff --git a/lib/irb/helper_method/conf.rb b/lib/irb/helper_method/conf.rb
deleted file mode 100644
index 718ed279c0..0000000000
--- a/lib/irb/helper_method/conf.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module IRB
- module HelperMethod
- class Conf < Base
- description "Returns the current IRB context."
-
- def execute
- IRB.CurrentContext
- end
- end
- end
-end
diff --git a/lib/irb/history.rb b/lib/irb/history.rb
deleted file mode 100644
index 685354b2d8..0000000000
--- a/lib/irb/history.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-require "pathname"
-
-module IRB
- module HistorySavingAbility # :nodoc:
- def support_history_saving?
- true
- end
-
- def reset_history_counter
- @loaded_history_lines = self.class::HISTORY.size
- 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 history_file && 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
-
- # When HOME and XDG_CONFIG_HOME are not available, history_file might be nil
- return 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
-
- pathname = Pathname.new(history_file)
- unless Dir.exist?(pathname.dirname)
- warn "Warning: The directory to save IRB's history file does not exist. Please double check `IRB.conf[:HISTORY_FILE]`'s value."
- return
- end
-
- File.open(history_file, (append_history ? 'a' : 'w'), 0o600, encoding: IRB.conf[:LC_MESSAGES]&.encoding) do |f|
- hist = history.map{ |l| l.scrub.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 infinity
- end
- end
- f.puts(hist)
- end
- end
- end
- end
-end
diff --git a/lib/irb/init.rb b/lib/irb/init.rb
index 355047519c..55453cc8f7 100644
--- a/lib/irb/init.rb
+++ b/lib/irb/init.rb
@@ -1,50 +1,16 @@
-# frozen_string_literal: true
+# 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 = {}
- @INITIALIZED = false
- # 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
-
- def IRB.initialized?
- !!@INITIALIZED
- end
# initialize config
def IRB.setup(ap_path, argv: ::ARGV)
@@ -57,16 +23,17 @@ module IRB # :nodoc:
unless @CONF[:PROMPT][@CONF[:PROMPT_MODE]]
fail UndefinedPromptMode, @CONF[:PROMPT_MODE]
end
- @INITIALIZED = true
end
# @CONF default setting
def IRB.init_config(ap_path)
+ # class instance variables
+ @TRACER_INITIALIZED = false
+
# default configurations
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"
@@ -79,13 +46,11 @@ 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] = ENV.fetch("IRB_COMPLETOR", "regexp").to_sym
@CONF[:INSPECT_MODE] = true
@CONF[:USE_TRACER] = false
@CONF[:USE_LOADER] = false
@CONF[:IGNORE_SIGINT] = true
@CONF[:IGNORE_EOF] = false
- @CONF[:USE_PAGER] = true
@CONF[:EXTRA_DOC_DIRS] = []
@CONF[:ECHO] = nil
@CONF[:ECHO_ON_ASSIGNMENT] = nil
@@ -99,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",
@@ -130,6 +100,7 @@ module IRB # :nodoc:
},
:XMP => {
:PROMPT_I => nil,
+ :PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => " ==>%s\n"
@@ -192,6 +163,10 @@ module IRB # :nodoc:
# Symbol aliases
:'$' => :show_source,
:'@' => :whereami,
+ # Keyword aliases
+ :break => :irb_break,
+ :catch => :irb_catch,
+ :next => :irb_next,
}
end
@@ -218,7 +193,6 @@ module IRB # :nodoc:
added = [:TIME, IRB.conf[:MEASURE_PROC][:TIME], arg]
end
if added
- IRB.conf[:MEASURE] = true
found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] }
if found
# already added
@@ -239,7 +213,6 @@ module IRB # :nodoc:
type_sym = type.upcase.to_sym
IRB.conf[:MEASURE_CALLBACKS].reject!{ |t, | t == type_sym }
end
- IRB.conf[:MEASURE] = nil if IRB.conf[:MEASURE_CALLBACKS].empty?
end
def IRB.init_error
@@ -287,8 +260,6 @@ module IRB # :nodoc:
end
when "--noinspect"
@CONF[:INSPECT_MODE] = false
- when "--no-pager"
- @CONF[:USE_PAGER] = false
when "--singleline", "--readline", "--legacy"
@CONF[:USE_SINGLELINE] = true
when "--nosingleline", "--noreadline"
@@ -334,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
@@ -392,39 +359,61 @@ module IRB # :nodoc:
$LOAD_PATH.unshift(*load_path)
end
- # Run the config file
+ # running config
def IRB.run_config
if @CONF[:RC]
- irbrc_files.each do |rc|
- load rc
- rescue StandardError, ScriptError => e
- warn "Error loading RC file '#{rc}':\n#{e.full_message(highlight: false)}"
+ begin
+ load rc_file
+ rescue LoadError, Errno::ENOENT
+ rescue # StandardError, ScriptError
+ print "load error: #{rc_file}\n"
+ print $!.class, ": ", $!, "\n"
+ for err in $@[0, $@.size - 2]
+ print "\t", err, "\n"
+ end
end
end
end
IRBRC_EXT = "rc"
-
- def IRB.rc_file(ext)
- prepare_irbrc_name_generators
-
- # When irbrc exist in default location
- if (rcgen = @existing_rc_name_generators.first)
- return rcgen.call(ext)
+ def IRB.rc_file(ext = IRBRC_EXT)
+ if !@CONF[:RC_NAME_GENERATOR]
+ rc_file_generators do |rcgen|
+ @CONF[:RC_NAME_GENERATOR] ||= rcgen
+ if File.exist?(rcgen.call(IRBRC_EXT))
+ @CONF[:RC_NAME_GENERATOR] = rcgen
+ break
+ end
+ end
end
-
- # When irbrc does not exist in default location
- rc_file_generators do |rcgen|
- return rcgen.call(ext)
+ case rc_file = @CONF[:RC_NAME_GENERATOR].call(ext)
+ when String
+ return rc_file
+ else
+ fail IllegalRCNameGenerator
end
-
- # When HOME and XDG_CONFIG_HOME are not available
- nil
end
- def IRB.irbrc_files
- prepare_irbrc_name_generators
- @irbrc_files
+ # enumerate possible rc-file base name generators
+ def IRB.rc_file_generators
+ if irbrc = ENV["IRBRC"]
+ yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc}
+ end
+ if xdg_config_home = ENV["XDG_CONFIG_HOME"]
+ irb_home = File.join(xdg_config_home, "irb")
+ if File.directory?(irb_home)
+ yield proc{|rc| irb_home + "/irb#{rc}"}
+ end
+ end
+ if home = ENV["HOME"]
+ yield proc{|rc| home+"/.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}"}
+ yield proc{|rc| current_dir+"/$irb#{rc}"}
end
# loading modules
@@ -438,52 +427,10 @@ module IRB # :nodoc:
end
end
+
+ DefaultEncodings = Struct.new(:external, :internal)
class << IRB
private
-
- def prepare_irbrc_name_generators
- return if @existing_rc_name_generators
-
- @existing_rc_name_generators = []
- @irbrc_files = []
- rc_file_generators do |rcgen|
- irbrc = rcgen.call(IRBRC_EXT)
- if File.exist?(irbrc)
- @irbrc_files << irbrc
- @existing_rc_name_generators << rcgen
- end
- end
- generate_current_dir_irbrc_files.each do |irbrc|
- @irbrc_files << irbrc if File.exist?(irbrc)
- end
- @irbrc_files.uniq!
- end
-
- # enumerate possible rc-file base name generators
- def rc_file_generators
- if irbrc = ENV["IRBRC"]
- yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc}
- end
- if xdg_config_home = ENV["XDG_CONFIG_HOME"]
- irb_home = File.join(xdg_config_home, "irb")
- if File.directory?(irb_home)
- yield proc{|rc| irb_home + "/irb#{rc}"}
- end
- end
- if home = ENV["HOME"]
- yield proc{|rc| home+"/.irb#{rc}"}
- if xdg_config_home.nil? || xdg_config_home.empty?
- yield proc{|rc| home+"/.config/irb/irb#{rc}"}
- end
- end
- end
-
- # possible irbrc files in current directory
- def generate_current_dir_irbrc_files
- current_dir = Dir.pwd
- %w[.irbrc irbrc _irbrc $irbrc].map { |file| "#{current_dir}/#{file}" }
- end
-
def set_encoding(extern, intern = nil, override: true)
verbose, $VERBOSE = $VERBOSE, nil
Encoding.default_external = extern unless extern.nil? || extern.empty?
diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb
index 684527edc4..9480573195 100644
--- a/lib/irb/input-method.rb
+++ b/lib/irb/input-method.rb
@@ -1,17 +1,30 @@
-# frozen_string_literal: true
+# 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
@@ -20,7 +33,7 @@ module IRB
#
# See IO#gets for more information.
def gets
- fail NotImplementedError
+ fail NotImplementedError, "gets"
end
public :gets
@@ -40,14 +53,6 @@ module IRB
false
end
- def support_history_saving?
- false
- end
-
- def prompting?
- false
- end
-
# For debug message
def inspect
'Abstract InputMethod'
@@ -57,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 => "-")
@@ -67,7 +73,6 @@ module IRB
#
# See IO#gets for more information.
def gets
- puts if @stdout.tty? # workaround for debug compatibility test
print @prompt
line = @stdin.gets
@line[@line_no += 1] = line
@@ -96,10 +101,6 @@ module IRB
true
end
- def prompting?
- STDIN.tty?
- end
-
# Returns the current line number for #io.
#
# #line counts the number of times #gets is called.
@@ -135,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.
@@ -170,99 +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
- def prompting?
- true
- end
+ # 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
+ # 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: |
@@ -275,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
@@ -304,164 +318,98 @@ module IRB
@auto_indent_proc = block
end
- def retrieve_doc_namespace(matched)
- preposing, _target, postposing, bind = @completion_params
- @completor.doc_namespace(preposing, matched, postposing, bind: bind)
- end
-
- def rdoc_ri_driver
- return @rdoc_ri_driver if defined?(@rdoc_ri_driver)
+ 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.
+ ]
- begin
- require 'rdoc'
- rescue LoadError
- @rdoc_ri_driver = nil
- else
- options = {}
- options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
- @rdoc_ri_driver = RDoc::RI::Driver.new(options)
+ if just_cursor_moving and completion_journey_data.nil?
+ return nil
end
- 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)
- def show_doc_dialog_proc
- input_method = self # self is changed in the lambda below.
- ->() {
- 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
+ options = {}
+ options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
+ driver = RDoc::RI::Driver.new(options)
- name = input_method.retrieve_doc_namespace(result[pointer])
- # Use first one because document dialog does not support multiple namespaces.
- name = name.first if name.is_a?(Array)
-
- show_easter_egg = name&.match?(/\ARubyVM/) && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
-
- driver = input_method.rdoc_ri_driver
-
- 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 = rdoc_ri_driver
- return unless driver
-
- if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
- IRB.__send__(:easter_egg)
- return
- end
-
- namespace = retrieve_doc_namespace(matched)
- return unless namespace
-
- 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.
#
@@ -471,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
@@ -488,15 +436,37 @@ module IRB
@eof
end
- def prompting?
+ # 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 667087ccba..d8c0ba90cf 100644
--- a/lib/irb/inspector.rb
+++ b/lib/irb/inspector.rb
@@ -1,8 +1,15 @@
-# frozen_string_literal: true
+# 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
@@ -46,7 +52,7 @@ module IRB # :nodoc:
# Determines the inspector to use where +inspector+ is one of the keys passed
# during inspector definition.
def self.keys_with_inspector(inspector)
- INSPECTORS.select{|k, v| v == inspector}.collect{|k, v| k}
+ INSPECTORS.select{|k,v| v == inspector}.collect{|k, v| k}
end
# Example
@@ -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
@@ -113,7 +111,7 @@ module IRB # :nodoc:
Color.colorize_code(v.inspect, colorable: Color.colorable? && Color.inspect_colorable?(v))
}
Inspector.def_inspector([true, :pp, :pretty_inspect], proc{require_relative "color_printer"}){|v|
- IRB::ColorPrinter.pp(v, +'').chomp
+ IRB::ColorPrinter.pp(v, '').chomp
}
Inspector.def_inspector([:yaml, :YAML], proc{require "yaml"}){|v|
begin
diff --git a/lib/irb/irb.gemspec b/lib/irb/irb.gemspec
index b29002f593..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.4.2"
- spec.add_dependency "rdoc", ">= 4.0.0"
+ spec.add_dependency "reline", ">= 0.3.0"
end
diff --git a/lib/irb/lc/error.rb b/lib/irb/lc/error.rb
index ee0f047822..cb5c21cdb4 100644
--- a/lib/irb/lc/error.rb
+++ b/lib/irb/lc/error.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/lc/error.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB
# :stopdoc:
@@ -12,6 +18,11 @@ module IRB
super("Unrecognized switch: #{val}")
end
end
+ class NotImplementedError < StandardError
+ def initialize(val)
+ super("Need to define `#{val}'")
+ end
+ end
class CantReturnToNormalMode < StandardError
def initialize
super("Can't return to normal mode.")
@@ -47,6 +58,11 @@ module IRB
super("Undefined prompt mode(#{val}).")
end
end
+ class IllegalRCGenerator < StandardError
+ def initialize
+ super("Define illegal RC_NAME_GENERATOR.")
+ end
+ end
# :startdoc:
end
diff --git a/lib/irb/lc/help-message b/lib/irb/lc/help-message
index 37347306e8..5b23f4c41e 100644
--- a/lib/irb/lc/help-message
+++ b/lib/irb/lc/help-message
@@ -22,18 +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.
- --no-pager Don't use pager.
- --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 9e2e5b8870..5e3622cbae 100644
--- a/lib/irb/lc/ja/error.rb
+++ b/lib/irb/lc/ja/error.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
-#
+# -*- 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:
@@ -12,6 +18,11 @@ module IRB
super("スイッチ(#{val})が分りません")
end
end
+ class NotImplementedError < StandardError
+ def initialize(val)
+ super("`#{val}'の定義が必要です")
+ end
+ end
class CantReturnToNormalMode < StandardError
def initialize
super("Normalモードに戻れません.")
@@ -47,6 +58,11 @@ module IRB
super("プロンプトモード(#{val})は定義されていません.")
end
end
+ class IllegalRCGenerator < StandardError
+ def initialize
+ super("RC_NAME_GENERATORが正しく定義されていません.")
+ end
+ end
# :startdoc:
end
diff --git a/lib/irb/lc/ja/help-message b/lib/irb/lc/ja/help-message
index 99f4449b3b..1c15d331ea 100644
--- a/lib/irb/lc/ja/help-message
+++ b/lib/irb/lc/ja/help-message
@@ -9,18 +9,10 @@ Usage: irb.rb [options] [programfile] [arguments]
-W[level=2] ruby -W と同じ.
--context-mode n 新しいワークスペースを作成した時に関連する Binding
オブジェクトの作成方法を 0 から 3 のいずれかに設定する.
- --extra-doc-dir 指定したディレクトリのドキュメントを追加で読み込む.
--echo 実行結果を表示する(デフォルト).
--noecho 実行結果を表示しない.
- --echo-on-assignment
- 代入結果を表示する.
- --noecho-on-assignment
- 代入結果を表示しない.
- --truncate-echo-on-assignment
- truncateされた代入結果を表示する(デフォルト).
--inspect 結果出力にinspectを用いる.
--noinspect 結果出力にinspectを用いない.
- --no-pager ページャを使用しない.
--multiline マルチラインエディタを利用する.
--nomultiline マルチラインエディタを利用しない.
--singleline シングルラインエディタを利用する.
@@ -29,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が
@@ -42,8 +31,6 @@ Usage: irb.rb [options] [programfile] [arguments]
--sample-book-mode/--simple-prompt
非常にシンプルなプロンプトを用いるモードです.
--noprompt プロンプト表示を行なわない.
- --script スクリプトモード(最初の引数をスクリプトファイルとして扱う、デフォルト)
- --noscript 引数をargvとして扱う.
--single-irb irb 中で self を実行して得られるオブジェクトをサ
ブ irb と共有する.
--tracer コマンド実行時にトレースを行なう.
diff --git a/lib/irb/locale.rb b/lib/irb/locale.rb
index 2abcc7354b..bb44b41002 100644
--- a/lib/irb/locale.rb
+++ b/lib/irb/locale.rb
@@ -1,9 +1,14 @@
-# frozen_string_literal: true
+# 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,19 +83,46 @@ 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}"
end
end
- def find(file, paths = $:)
+ def find(file , paths = $:)
dir = File.dirname(file)
dir = "" if dir == "."
base = File.basename(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 5aa940cc28..0000000000
--- a/lib/irb/nesting_parser.rb
+++ /dev/null
@@ -1,237 +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_alias_undef
- skip = t.event == :on_kw
- 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 receiver.f;
- body = :normal
- when :on_lparen
- # def receiver.f()
- next_args << :eq
- else
- if t.event == :on_op && t.tok == '='
- # def receiver.f =
- body = :oneliner
- else
- # def receiver.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 'alias'
- opens << [t, :in_alias_undef, 2]
- when 'undef'
- opens << [t, :in_alias_undef, 1]
- 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
- if opens.last && opens.last[1] == :in_alias_undef && !IGNORE_TOKENS.include?(t.event) && t.event != :on_heredoc_end
- tok, state, arg = opens.pop
- opens << [tok, state, arg - 1] if arg >= 1
- 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 dc1b9ef14b..d0e413dd68 100644
--- a/lib/irb/notifier.rb
+++ b/lib/irb/notifier.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# 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 69942f47a2..3fda708cb0 100644
--- a/lib/irb/output-method.rb
+++ b/lib/irb/output-method.rb
@@ -1,18 +1,30 @@
-# frozen_string_literal: true
+# 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
# IRB::Notifier. You can define your own output method to use with Irb.new,
# or Context.new
class OutputMethod
+ class NotImplementedError < StandardError
+ def initialize(val)
+ super("Need to define `#{val}'")
+ end
+ end
+
# Open this method to implement your own output method, raises a
# NotImplementedError if you don't define #print in your own class.
def print(*opts)
- raise NotImplementedError
+ raise NotImplementedError, "print"
end
# Prints the given +opts+, with a newline delimiter.
diff --git a/lib/irb/pager.rb b/lib/irb/pager.rb
deleted file mode 100644
index 3391b32c66..0000000000
--- a/lib/irb/pager.rb
+++ /dev/null
@@ -1,91 +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, **options)
- if content_exceeds_screen_height?(content)
- page(**options) do |io|
- io.puts content
- end
- else
- $stdout.puts content
- end
- end
-
- def page(retain_content: false)
- if should_page? && pager = setup_pager(retain_content: retain_content)
- 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 should_page?
- IRB.conf[:USE_PAGER] && STDIN.tty? && (ENV.key?("TERM") && ENV["TERM"] != "dumb")
- end
-
- 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(retain_content:)
- require 'shellwords'
-
- PAGE_COMMANDS.each do |pager_cmd|
- cmd = Shellwords.split(pager_cmd)
- next if cmd.empty?
-
- if cmd.first == 'less'
- cmd << '-R' unless cmd.include?('-R')
- cmd << '-X' if retain_content && !cmd.include?('-X')
- end
-
- begin
- io = IO.popen(cmd, '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 cfe36be83f..85b336fbe1 100644
--- a/lib/irb/ruby-lex.rb
+++ b/lib/irb/ruby-lex.rb
@@ -1,124 +1,165 @@
-# frozen_string_literal: true
+# 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 unless t.tok == 'alias' || t.tok == 'undef'
+ 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 5d7d729d19..0000000000
--- a/lib/irb/source_finder.rb
+++ /dev/null
@@ -1,139 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "ruby-lex"
-
-module IRB
- class SourceFinder
- class EvaluationError < StandardError; end
-
- class Source
- attr_reader :file, :line
- def initialize(file, line, ast_source = nil)
- @file = file
- @line = line
- @ast_source = ast_source
- end
-
- def file_exist?
- File.exist?(@file)
- end
-
- def binary_file?
- # If the line is zero, it means that the target's source is probably in a binary file.
- @line.zero?
- end
-
- def file_content
- @file_content ||= File.read(@file)
- end
-
- def colorized_content
- if !binary_file? && file_exist?
- end_line = find_end
- # To correctly colorize, we need to colorize full content and extract the relevant lines.
- colored = IRB::Color.colorize_code(file_content)
- colored.lines[@line - 1...end_line].join
- elsif @ast_source
- IRB::Color.colorize_code(@ast_source)
- end
- end
-
- private
-
- def find_end
- lex = RubyLex.new
- code = file_content
- lines = code.lines[(@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 @line + lnum
- end
- end
- @line
- end
- end
-
- private_constant :Source
-
- def initialize(irb_context)
- @irb_context = irb_context
- end
-
- def find_source(signature, super_level = 0)
- case signature
- when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # ConstName, ::ConstName, ConstPath::ConstName
- eval_receiver_or_owner(signature) # trigger autoload
- *parts, name = signature.split('::', -1)
- base =
- if parts.empty? # ConstName
- find_const_owner(name)
- elsif parts == [''] # ::ConstName
- Object
- else # ConstPath::ConstName
- eval_receiver_or_owner(parts.join('::'))
- end
- file, line = base.const_source_location(name)
- when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
- owner = eval_receiver_or_owner(Regexp.last_match[:owner])
- method = Regexp.last_match[:method]
- return unless owner.respond_to?(:instance_method)
- method = method_target(owner, super_level, method, "owner")
- file, line = method&.source_location
- when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
- receiver = eval_receiver_or_owner(Regexp.last_match[:receiver] || 'self')
- method = Regexp.last_match[:method]
- return unless receiver.respond_to?(method, true)
- method = method_target(receiver, super_level, method, "receiver")
- file, line = method&.source_location
- end
- return unless file && line
-
- if File.exist?(file)
- Source.new(file, line)
- elsif method
- # Method defined with eval, probably in IRB session
- source = RubyVM::AbstractSyntaxTree.of(method)&.source rescue nil
- Source.new(file, line, source)
- end
- rescue EvaluationError
- nil
- end
-
- private
-
- def method_target(owner_receiver, super_level, method, type)
- case type
- when "owner"
- target_method = owner_receiver.instance_method(method)
- when "receiver"
- target_method = owner_receiver.method(method)
- end
- super_level.times do |s|
- target_method = target_method.super_method if target_method
- end
- target_method
- rescue NameError
- nil
- end
-
- def eval_receiver_or_owner(code)
- context_binding = @irb_context.workspace.binding
- eval(code, context_binding)
- rescue NameError
- raise EvaluationError
- end
-
- def find_const_owner(name)
- module_nesting = @irb_context.workspace.binding.eval('::Module.nesting')
- module_nesting.find { |mod| mod.const_defined?(name, false) } || module_nesting.find { |mod| mod.const_defined?(name) } || Object
- 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 a3391c12a3..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
-
- class EmptyInput < Statement
- def is_assignment?
- false
- end
-
- def suppresses_echo?
- true
- end
-
- # Debugger takes empty input to repeat the last command
- def should_be_handled_by_debugger?
- true
- end
-
- def code
- ""
- end
- 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
- end
-
- class Command < Statement
- attr_reader :command_class, :arg
-
- def initialize(original_code, command_class, arg)
- @code = original_code
- @command_class = command_class
- @arg = arg
- end
-
- def is_assignment?
- false
- end
-
- def suppresses_echo?
- false
- end
-
- def should_be_handled_by_debugger?
- require_relative 'command/debug'
- IRB::Command::DebugCommand > @command_class
- end
- end
- end
-end
diff --git a/lib/irb/version.rb b/lib/irb/version.rb
index c41917329c..d1c0e54fdc 100644
--- a/lib/irb/version.rb
+++ b/lib/irb/version.rb
@@ -1,11 +1,17 @@
-# frozen_string_literal: true
+# 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.13.1"
+ VERSION = "1.6.2"
@RELEASE_VERSION = VERSION
- @LAST_UPDATE_DATE = "2024-05-05"
+ @LAST_UPDATE_DATE = "2022-12-13"
end
diff --git a/lib/irb/workspace.rb b/lib/irb/workspace.rb
index d24d1cc38d..e5ef52528a 100644
--- a/lib/irb/workspace.rb
+++ b/lib/irb/workspace.rb
@@ -1,13 +1,17 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/workspace-binding.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require "delegate"
-require_relative "helper_method"
-
IRB::TOPLEVEL_BINDING = binding
module IRB # :nodoc:
class WorkSpace
@@ -92,11 +96,11 @@ EOF
IRB.conf[:__MAIN__] = @main
@main.singleton_class.class_eval do
private
+ define_method(:exit) do |*a, &b|
+ # Do nothing, will be overridden
+ end
define_method(:binding, Kernel.instance_method(:binding))
define_method(:local_variables, Kernel.instance_method(:local_variables))
- # Define empty method to avoid delegator warning, will be overridden.
- define_method(:exit) {|*a, &b| }
- define_method(:exit!) {|*a, &b| }
end
@binding = eval("IRB.conf[:__MAIN__].instance_eval('binding', __FILE__, __LINE__)", @binding, *@binding.source_location)
end
@@ -110,14 +114,8 @@ EOF
# <code>IRB.conf[:__MAIN__]</code>
attr_reader :main
- def load_helper_methods_to_main
- ancestors = class<<main;ancestors;end
- main.extend ExtendCommandBundle if !ancestors.include?(ExtendCommandBundle)
- main.extend HelpersContainer if !ancestors.include?(HelpersContainer)
- 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
@@ -130,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/
@@ -146,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('')
@@ -173,17 +173,8 @@ EOF
"\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n"
end
- end
- module HelpersContainer
- def self.install_helper_methods
- HelperMethod.helper_methods.each do |name, helper_method_class|
- define_method name do |*args, **opts, &block|
- helper_method_class.instance.execute(*args, **opts, &block)
- end unless method_defined?(name)
- end
+ def IRB.delete_caller
end
-
- install_helper_methods
end
end
diff --git a/lib/irb/ws-for-case-2.rb b/lib/irb/ws-for-case-2.rb
index 03f42d73d9..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: true
+# 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 b1bc53283e..88cbd88525 100644
--- a/lib/irb/xmp.rb
+++ b/lib/irb/xmp.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# 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"
@@ -44,8 +50,8 @@ class XMP
# The top-level binding or, optional +bind+ parameter will be used when
# creating the workspace. See WorkSpace.new for more information.
#
- # This uses the +:XMP+ prompt mode.
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # This uses the +:XMP+ prompt mode, see IRB@Customizing+the+IRB+Prompt for
+ # full detail.
def initialize(bind = nil)
IRB.init_config(nil)
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 387df4b8f4..47e62d6e70 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# = net/http.rb
#
@@ -34,69 +34,71 @@ module Net #:nodoc:
# \Class \Net::HTTP provides a rich library that implements the client
# in a client-server model that uses the \HTTP request-response protocol.
- # For information about \HTTP, see:
+ # For information about \HTTP, see
#
# - {Hypertext Transfer Protocol}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol].
# - {Technical overview}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Technical_overview].
#
- # == About the Examples
+ # Note: If you are performing only a few GET requests, consider using
+ # {OpenURI}[rdoc-ref:OpenURI];
+ # otherwise, read on.
#
- # :include: doc/net-http/examples.rdoc
+ # == Synopsis
#
- # == Strategies
- #
- # - If you will make only a few GET requests,
- # consider using {OpenURI}[rdoc-ref:OpenURI].
- # - If you will make only a few requests of all kinds,
- # consider using the various singleton convenience methods in this class.
- # Each of the following methods automatically starts and finishes
- # a {session}[rdoc-ref:Net::HTTP@Sessions] that sends a single request:
- #
- # # Return string response body.
- # Net::HTTP.get(hostname, path)
- # Net::HTTP.get(uri)
- #
- # # Write string response body to $stdout.
- # Net::HTTP.get_print(hostname, path)
- # Net::HTTP.get_print(uri)
- #
- # # Return response as Net::HTTPResponse object.
- # Net::HTTP.get_response(hostname, path)
- # Net::HTTP.get_response(uri)
- # data = '{"title": "foo", "body": "bar", "userId": 1}'
- # Net::HTTP.post(uri, data)
- # params = {title: 'foo', body: 'bar', userId: 1}
- # Net::HTTP.post_form(uri, params)
- #
- # - If performance is important, consider using sessions, which lower request overhead.
- # This {session}[rdoc-ref:Net::HTTP@Sessions] has multiple requests for
- # {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods]
- # and {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
- #
- # Net::HTTP.start(hostname) do |http|
- # # Session started automatically before block execution.
- # http.get(path)
- # http.head(path)
- # body = 'Some text'
- # http.post(path, body) # Can also have a block.
- # http.put(path, body)
- # http.delete(path)
- # http.options(path)
- # http.trace(path)
- # http.patch(path, body) # Can also have a block.
- # http.copy(path)
- # http.lock(path, body)
- # http.mkcol(path, body)
- # http.move(path)
- # http.propfind(path, body)
- # http.proppatch(path, body)
- # http.unlock(path, body)
- # # Session finished automatically at block exit.
- # end
+ # If you are already familiar with \HTTP, this synopsis may be helpful.
+ #
+ # {Session}[rdoc-ref:Net::HTTP@Sessions] with multiple requests for
+ # {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods]:
+ #
+ # Net::HTTP.start(hostname) do |http|
+ # # Session started automatically before block execution.
+ # http.get(path_or_uri, headers = {})
+ # http.head(path_or_uri, headers = {})
+ # http.post(path_or_uri, data, headers = {}) # Can also have a block.
+ # http.put(path_or_uri, data, headers = {})
+ # http.delete(path_or_uri, headers = {Depth: 'Infinity'})
+ # http.options(path_or_uri, headers = {})
+ # http.trace(path_or_uri, headers = {})
+ # http.patch(path_or_uri, data, headers = {}) # Can also have a block.
+ # # Session finished automatically at block exit.
+ # end
+ #
+ # {Session}[rdoc-ref:Net::HTTP@Sessions] with multiple requests for
+ # {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
+ #
+ # Net::HTTP.start(hostname) do |http|
+ # # Session started automatically before block execution.
+ # http.copy(path_or_uri, headers = {})
+ # http.lock(path_or_uri, body, headers = {})
+ # http.mkcol(path_or_uri, body = nil, headers = {})
+ # http.move(path_or_uri, headers = {})
+ # http.propfind(path_or_uri, body = nil, headers = {'Depth' => '0'})
+ # http.proppatch(path_or_uri, body, headers = {})
+ # http.unlock(path_or_uri, body, headers = {})
+ # # Session finished automatically at block exit.
+ # end
+ #
+ # Each of the following methods automatically starts and finishes
+ # a {session}[rdoc-ref:Net::HTTP@Sessions] that sends a single request:
+ #
+ # # Return string response body.
+ # Net::HTTP.get(hostname, path, port = 80)
+ # Net::HTTP.get(uri, headers = {}, port = 80)
#
- # The methods cited above are convenience methods that, via their few arguments,
- # allow minimal control over the requests.
- # For greater control, consider using {request objects}[rdoc-ref:Net::HTTPRequest].
+ # # Write string response body to $stdout.
+ # Net::HTTP.get_print(hostname, path_or_uri, port = 80)
+ # Net::HTTP.get_print(uri, headers = {}, port = 80)
+ #
+ # # Return response as Net::HTTPResponse object.
+ # Net::HTTP.get_response(hostname, path_or_uri, port = 80)
+ # Net::HTTP.get_response(uri, headers = {}, port = 80)
+ #
+ # Net::HTTP.post(uri, data, headers = {})
+ # Net::HTTP.post_form(uri, params)
+ #
+ # == About the Examples
+ #
+ # :include: doc/net-http/examples.rdoc
#
# == URIs
#
@@ -173,7 +175,7 @@ module Net #:nodoc:
# {Request Fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields].
# A host may also accept other custom fields.
#
- # == \HTTP Sessions
+ # == Sessions
#
# A _session_ is a connection between a server (host) and a client that:
#
@@ -181,7 +183,7 @@ module Net #:nodoc:
# - May contain any number of requests.
# - Is ended by instance method Net::HTTP#finish.
#
- # See example sessions at {Strategies}[rdoc-ref:Net::HTTP@Strategies].
+ # See example sessions at the {Synopsis}[rdoc-ref:Net::HTTP@Synopsis].
#
# === Session Using \Net::HTTP.start
#
@@ -262,55 +264,66 @@ module Net #:nodoc:
#
# == Following Redirection
#
- # Each returned response is an instance of a subclass of Net::HTTPResponse.
- # See the {response class hierarchy}[rdoc-ref:Net::HTTPResponse@Response+Subclasses].
+ # Each Net::HTTPResponse object belongs to a class for its response code.
#
- # In particular, class Net::HTTPRedirection is the parent
- # of all redirection classes.
- # This allows you to craft a case statement to handle redirections properly:
+ # For example, all 2XX responses are instances of a Net::HTTPSuccess
+ # subclass, a 3XX response is an instance of a Net::HTTPRedirection
+ # subclass and a 200 response is an instance of the Net::HTTPOK class. For
+ # details of response classes, see the section "HTTP Response Classes"
+ # below.
#
- # def fetch(uri, limit = 10)
+ # Using a case statement you can handle various types of responses properly:
+ #
+ # def fetch(uri_str, limit = 10)
# # You should choose a better exception.
- # raise ArgumentError, 'Too many HTTP redirects' if limit == 0
- #
- # res = Net::HTTP.get_response(URI(uri))
- # case res
- # when Net::HTTPSuccess # Any success class.
- # res
- # when Net::HTTPRedirection # Any redirection class.
- # location = res['Location']
- # warn "Redirected to #{location}"
+ # raise ArgumentError, 'too many HTTP redirects' if limit == 0
+ #
+ # response = Net::HTTP.get_response(URI(uri_str))
+ #
+ # case response
+ # when Net::HTTPSuccess then
+ # response
+ # when Net::HTTPRedirection then
+ # location = response['location']
+ # warn "redirected to #{location}"
# fetch(location, limit - 1)
- # else # Any other class.
- # res.value
+ # else
+ # response.value
# end
# end
#
- # fetch(uri)
+ # print fetch('http://www.ruby-lang.org')
#
# == Basic Authentication
#
# Basic authentication is performed according to
- # {RFC2617}[http://www.ietf.org/rfc/rfc2617.txt]:
+ # [RFC2617](http://www.ietf.org/rfc/rfc2617.txt).
+ #
+ # uri = URI('http://example.com/index.html?key=value')
#
# req = Net::HTTP::Get.new(uri)
- # req.basic_auth('user', 'pass')
- # res = Net::HTTP.start(hostname) do |http|
+ # req.basic_auth 'user', 'pass'
+ #
+ # res = Net::HTTP.start(uri.hostname, uri.port) {|http|
# http.request(req)
- # end
+ # }
+ # puts res.body
#
# == Streaming Response Bodies
#
- # By default \Net::HTTP reads an entire response into memory. If you are
+ # By default Net::HTTP reads an entire response into memory. If you are
# handling large files or wish to implement a progress bar you can instead
# stream the body directly to an IO.
#
- # Net::HTTP.start(hostname) do |http|
- # req = Net::HTTP::Get.new(uri)
- # http.request(req) do |res|
- # open('t.tmp', 'w') do |f|
- # res.read_body do |chunk|
- # f.write chunk
+ # uri = URI('http://example.com/large_file')
+ #
+ # Net::HTTP.start(uri.host, uri.port) do |http|
+ # request = Net::HTTP::Get.new uri
+ #
+ # http.request request do |response|
+ # open 'large_file', 'w' do |io|
+ # response.read_body do |chunk|
+ # io.write chunk
# end
# end
# end
@@ -318,411 +331,56 @@ module Net #:nodoc:
#
# == HTTPS
#
- # HTTPS is enabled for an \HTTP connection by Net::HTTP#use_ssl=:
- #
- # Net::HTTP.start(hostname, :use_ssl => true) do |http|
- # req = Net::HTTP::Get.new(uri)
- # res = http.request(req)
- # end
- #
- # Or if you simply want to make a GET request, you may pass in a URI
- # object that has an \HTTPS URL. \Net::HTTP automatically turns on TLS
- # verification if the URI object has a 'https' URI scheme:
- #
- # uri # => #<URI::HTTPS https://jsonplaceholder.typicode.com/>
- # Net::HTTP.get(uri)
- #
- # == Proxy Server
- #
- # An \HTTP object can have
- # a {proxy server}[https://en.wikipedia.org/wiki/Proxy_server].
- #
- # You can create an \HTTP object with a proxy server
- # using method Net::HTTP.new or method Net::HTTP.start.
- #
- # The proxy may be defined either by argument +p_addr+
- # or by environment variable <tt>'http_proxy'</tt>.
- #
- # === Proxy Using Argument +p_addr+ as a \String
- #
- # When argument +p_addr+ is a string hostname,
- # the returned +http+ has the given host as its proxy:
+ # HTTPS is enabled for an HTTP connection by Net::HTTP#use_ssl=.
#
- # http = Net::HTTP.new(hostname, nil, 'proxy.example')
- # http.proxy? # => true
- # http.proxy_from_env? # => false
- # http.proxy_address # => "proxy.example"
- # # These use default values.
- # http.proxy_port # => 80
- # http.proxy_user # => nil
- # http.proxy_pass # => nil
+ # uri = URI('https://secure.example.com/some_path?query=string')
#
- # The port, username, and password for the proxy may also be given:
+ # Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
+ # request = Net::HTTP::Get.new uri
+ # response = http.request request # Net::HTTPResponse object
+ # end
#
- # http = Net::HTTP.new(hostname, nil, 'proxy.example', 8000, 'pname', 'ppass')
- # # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.proxy? # => true
- # http.proxy_from_env? # => false
- # http.proxy_address # => "proxy.example"
- # http.proxy_port # => 8000
- # http.proxy_user # => "pname"
- # http.proxy_pass # => "ppass"
+ # Or if you simply want to make a GET request, you may pass in an URI
+ # object that has an HTTPS URL. Net::HTTP automatically turns on TLS
+ # verification if the URI object has a 'https' URI scheme.
#
- # === Proxy Using '<tt>ENV['http_proxy']</tt>'
+ # uri = URI('https://example.com/')
+ # Net::HTTP.get(uri) # => String
#
- # When environment variable <tt>'http_proxy'</tt>
- # is set to a \URI string,
- # the returned +http+ will have the server at that URI as its proxy;
- # note that the \URI string must have a protocol
- # such as <tt>'http'</tt> or <tt>'https'</tt>:
+ # In previous versions of Ruby you would need to require 'net/https' to use
+ # HTTPS. This is no longer true.
#
- # ENV['http_proxy'] = 'http://example.com'
- # http = Net::HTTP.new(hostname)
- # http.proxy? # => true
- # http.proxy_from_env? # => true
- # http.proxy_address # => "example.com"
- # # These use default values.
- # http.proxy_port # => 80
- # http.proxy_user # => nil
- # http.proxy_pass # => nil
+ # == Proxies
#
- # The \URI string may include proxy username, password, and port number:
+ # Net::HTTP will automatically create a proxy from the +http_proxy+
+ # environment variable if it is present. To disable use of +http_proxy+,
+ # pass +nil+ for the proxy address.
#
- # ENV['http_proxy'] = 'http://pname:ppass@example.com:8000'
- # http = Net::HTTP.new(hostname)
- # http.proxy? # => true
- # http.proxy_from_env? # => true
- # http.proxy_address # => "example.com"
- # http.proxy_port # => 8000
- # http.proxy_user # => "pname"
- # http.proxy_pass # => "ppass"
+ # You may also create a custom proxy:
#
- # === Filtering Proxies
+ # proxy_addr = 'your.proxy.host'
+ # proxy_port = 8080
#
- # With method Net::HTTP.new (but not Net::HTTP.start),
- # you can use argument +p_no_proxy+ to filter proxies:
+ # Net::HTTP.new('example.com', nil, proxy_addr, proxy_port).start { |http|
+ # # always proxy via your.proxy.addr:8080
+ # }
#
- # - Reject a certain address:
+ # See Net::HTTP.new for further details and examples such as proxies that
+ # require a username and password.
#
- # http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example')
- # http.proxy_address # => nil
- #
- # - Reject certain domains or subdomains:
+ # == Compression
#
- # http = Net::HTTP.new('example.com', nil, 'my.proxy.example', 8000, 'pname', 'ppass', 'proxy.example')
- # http.proxy_address # => nil
+ # Net::HTTP automatically adds Accept-Encoding for compression of response
+ # bodies and automatically decompresses gzip and deflate responses unless a
+ # Range header was sent.
#
- # - Reject certain addresses and port combinations:
- #
- # http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:1234')
- # http.proxy_address # => "proxy.example"
- #
- # http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:8000')
- # http.proxy_address # => nil
- #
- # - Reject a list of the types above delimited using a comma:
- #
- # http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000')
- # http.proxy_address # => nil
- #
- # http = Net::HTTP.new('example.com', nil, 'my.proxy', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000')
- # http.proxy_address # => nil
- #
- # == Compression and Decompression
- #
- # \Net::HTTP does not compress the body of a request before sending.
- #
- # By default, \Net::HTTP adds header <tt>'Accept-Encoding'</tt>
- # to a new {request object}[rdoc-ref:Net::HTTPRequest]:
- #
- # Net::HTTP::Get.new(uri)['Accept-Encoding']
- # # => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
- #
- # This requests the server to zip-encode the response body if there is one;
- # the server is not required to do so.
- #
- # \Net::HTTP does not automatically decompress a response body
- # if the response has header <tt>'Content-Range'</tt>.
- #
- # Otherwise decompression (or not) depends on the value of header
- # {Content-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-encoding-response-header]:
- #
- # - <tt>'deflate'</tt>, <tt>'gzip'</tt>, or <tt>'x-gzip'</tt>:
- # decompresses the body and deletes the header.
- # - <tt>'none'</tt> or <tt>'identity'</tt>:
- # does not decompress the body, but deletes the header.
- # - Any other value:
- # leaves the body and header unchanged.
- #
- # == What's Here
- #
- # This is a categorized summary of methods and attributes.
- #
- # === \Net::HTTP Objects
- #
- # - {::new}[rdoc-ref:Net::HTTP.new]:
- # Creates a new instance.
- # - {#inspect}[rdoc-ref:Net::HTTP#inspect]:
- # Returns a string representation of +self+.
- #
- # === Sessions
- #
- # - {::start}[rdoc-ref:Net::HTTP.start]:
- # Begins a new session in a new \Net::HTTP object.
- # - {#started?}[rdoc-ref:Net::HTTP#started?]
- # (aliased as {#active?}[rdoc-ref:Net::HTTP#active?]):
- # Returns whether in a session.
- # - {#finish}[rdoc-ref:Net::HTTP#finish]:
- # Ends an active session.
- # - {#start}[rdoc-ref:Net::HTTP#start]:
- # Begins a new session in an existing \Net::HTTP object (+self+).
- #
- # === Connections
- #
- # - {:continue_timeout}[rdoc-ref:Net::HTTP#continue_timeout]:
- # Returns the continue timeout.
- # - {#continue_timeout=}[rdoc-ref:Net::HTTP#continue_timeout=]:
- # Sets the continue timeout seconds.
- # - {:keep_alive_timeout}[rdoc-ref:Net::HTTP#keep_alive_timeout]:
- # Returns the keep-alive timeout.
- # - {:keep_alive_timeout=}[rdoc-ref:Net::HTTP#keep_alive_timeout=]:
- # Sets the keep-alive timeout.
- # - {:max_retries}[rdoc-ref:Net::HTTP#max_retries]:
- # Returns the maximum retries.
- # - {#max_retries=}[rdoc-ref:Net::HTTP#max_retries=]:
- # Sets the maximum retries.
- # - {:open_timeout}[rdoc-ref:Net::HTTP#open_timeout]:
- # Returns the open timeout.
- # - {:open_timeout=}[rdoc-ref:Net::HTTP#open_timeout=]:
- # Sets the open timeout.
- # - {:read_timeout}[rdoc-ref:Net::HTTP#read_timeout]:
- # Returns the open timeout.
- # - {:read_timeout=}[rdoc-ref:Net::HTTP#read_timeout=]:
- # Sets the read timeout.
- # - {:ssl_timeout}[rdoc-ref:Net::HTTP#ssl_timeout]:
- # Returns the ssl timeout.
- # - {:ssl_timeout=}[rdoc-ref:Net::HTTP#ssl_timeout=]:
- # Sets the ssl timeout.
- # - {:write_timeout}[rdoc-ref:Net::HTTP#write_timeout]:
- # Returns the write timeout.
- # - {write_timeout=}[rdoc-ref:Net::HTTP#write_timeout=]:
- # Sets the write timeout.
- #
- # === Requests
- #
- # - {::get}[rdoc-ref:Net::HTTP.get]:
- # Sends a GET request and returns the string response body.
- # - {::get_print}[rdoc-ref:Net::HTTP.get_print]:
- # Sends a GET request and write the string response body to $stdout.
- # - {::get_response}[rdoc-ref:Net::HTTP.get_response]:
- # Sends a GET request and returns a response object.
- # - {::post_form}[rdoc-ref:Net::HTTP.post_form]:
- # Sends a POST request with form data and returns a response object.
- # - {::post}[rdoc-ref:Net::HTTP.post]:
- # Sends a POST request with data and returns a response object.
- # - {#copy}[rdoc-ref:Net::HTTP#copy]:
- # Sends a COPY request and returns a response object.
- # - {#delete}[rdoc-ref:Net::HTTP#delete]:
- # Sends a DELETE request and returns a response object.
- # - {#get}[rdoc-ref:Net::HTTP#get]:
- # Sends a GET request and returns a response object.
- # - {#head}[rdoc-ref:Net::HTTP#head]:
- # Sends a HEAD request and returns a response object.
- # - {#lock}[rdoc-ref:Net::HTTP#lock]:
- # Sends a LOCK request and returns a response object.
- # - {#mkcol}[rdoc-ref:Net::HTTP#mkcol]:
- # Sends a MKCOL request and returns a response object.
- # - {#move}[rdoc-ref:Net::HTTP#move]:
- # Sends a MOVE request and returns a response object.
- # - {#options}[rdoc-ref:Net::HTTP#options]:
- # Sends a OPTIONS request and returns a response object.
- # - {#patch}[rdoc-ref:Net::HTTP#patch]:
- # Sends a PATCH request and returns a response object.
- # - {#post}[rdoc-ref:Net::HTTP#post]:
- # Sends a POST request and returns a response object.
- # - {#propfind}[rdoc-ref:Net::HTTP#propfind]:
- # Sends a PROPFIND request and returns a response object.
- # - {#proppatch}[rdoc-ref:Net::HTTP#proppatch]:
- # Sends a PROPPATCH request and returns a response object.
- # - {#put}[rdoc-ref:Net::HTTP#put]:
- # Sends a PUT request and returns a response object.
- # - {#request}[rdoc-ref:Net::HTTP#request]:
- # Sends a request and returns a response object.
- # - {#request_get}[rdoc-ref:Net::HTTP#request_get]
- # (aliased as {#get2}[rdoc-ref:Net::HTTP#get2]):
- # Sends a GET request and forms a response object;
- # if a block given, calls the block with the object,
- # otherwise returns the object.
- # - {#request_head}[rdoc-ref:Net::HTTP#request_head]
- # (aliased as {#head2}[rdoc-ref:Net::HTTP#head2]):
- # Sends a HEAD request and forms a response object;
- # if a block given, calls the block with the object,
- # otherwise returns the object.
- # - {#request_post}[rdoc-ref:Net::HTTP#request_post]
- # (aliased as {#post2}[rdoc-ref:Net::HTTP#post2]):
- # Sends a POST request and forms a response object;
- # if a block given, calls the block with the object,
- # otherwise returns the object.
- # - {#send_request}[rdoc-ref:Net::HTTP#send_request]:
- # Sends a request and returns a response object.
- # - {#trace}[rdoc-ref:Net::HTTP#trace]:
- # Sends a TRACE request and returns a response object.
- # - {#unlock}[rdoc-ref:Net::HTTP#unlock]:
- # Sends an UNLOCK request and returns a response object.
- #
- # === Responses
- #
- # - {:close_on_empty_response}[rdoc-ref:Net::HTTP#close_on_empty_response]:
- # Returns whether to close connection on empty response.
- # - {:close_on_empty_response=}[rdoc-ref:Net::HTTP#close_on_empty_response=]:
- # Sets whether to close connection on empty response.
- # - {:ignore_eof}[rdoc-ref:Net::HTTP#ignore_eof]:
- # Returns whether to ignore end-of-file when reading a response body
- # with <tt>Content-Length</tt> headers.
- # - {:ignore_eof=}[rdoc-ref:Net::HTTP#ignore_eof=]:
- # Sets whether to ignore end-of-file when reading a response body
- # with <tt>Content-Length</tt> headers.
- # - {:response_body_encoding}[rdoc-ref:Net::HTTP#response_body_encoding]:
- # Returns the encoding to use for the response body.
- # - {#response_body_encoding=}[rdoc-ref:Net::HTTP#response_body_encoding=]:
- # Sets the response body encoding.
- #
- # === Proxies
- #
- # - {:proxy_address}[rdoc-ref:Net::HTTP#proxy_address]:
- # Returns the proxy address.
- # - {:proxy_address=}[rdoc-ref:Net::HTTP#proxy_address=]:
- # Sets the proxy address.
- # - {::proxy_class?}[rdoc-ref:Net::HTTP.proxy_class?]:
- # Returns whether +self+ is a proxy class.
- # - {#proxy?}[rdoc-ref:Net::HTTP#proxy?]:
- # Returns whether +self+ has a proxy.
- # - {#proxy_address}[rdoc-ref:Net::HTTP#proxy_address]
- # (aliased as {#proxyaddr}[rdoc-ref:Net::HTTP#proxyaddr]):
- # Returns the proxy address.
- # - {#proxy_from_env?}[rdoc-ref:Net::HTTP#proxy_from_env?]:
- # Returns whether the proxy is taken from an environment variable.
- # - {:proxy_from_env=}[rdoc-ref:Net::HTTP#proxy_from_env=]:
- # Sets whether the proxy is to be taken from an environment variable.
- # - {:proxy_pass}[rdoc-ref:Net::HTTP#proxy_pass]:
- # Returns the proxy password.
- # - {:proxy_pass=}[rdoc-ref:Net::HTTP#proxy_pass=]:
- # Sets the proxy password.
- # - {:proxy_port}[rdoc-ref:Net::HTTP#proxy_port]:
- # Returns the proxy port.
- # - {:proxy_port=}[rdoc-ref:Net::HTTP#proxy_port=]:
- # Sets the proxy port.
- # - {#proxy_user}[rdoc-ref:Net::HTTP#proxy_user]:
- # Returns the proxy user name.
- # - {:proxy_user=}[rdoc-ref:Net::HTTP#proxy_user=]:
- # Sets the proxy user.
- #
- # === Security
- #
- # - {:ca_file}[rdoc-ref:Net::HTTP#ca_file]:
- # Returns the path to a CA certification file.
- # - {:ca_file=}[rdoc-ref:Net::HTTP#ca_file=]:
- # Sets the path to a CA certification file.
- # - {:ca_path}[rdoc-ref:Net::HTTP#ca_path]:
- # Returns the path of to CA directory containing certification files.
- # - {:ca_path=}[rdoc-ref:Net::HTTP#ca_path=]:
- # Sets the path of to CA directory containing certification files.
- # - {:cert}[rdoc-ref:Net::HTTP#cert]:
- # Returns the OpenSSL::X509::Certificate object to be used for client certification.
- # - {:cert=}[rdoc-ref:Net::HTTP#cert=]:
- # Sets the OpenSSL::X509::Certificate object to be used for client certification.
- # - {:cert_store}[rdoc-ref:Net::HTTP#cert_store]:
- # Returns the X509::Store to be used for verifying peer certificate.
- # - {:cert_store=}[rdoc-ref:Net::HTTP#cert_store=]:
- # Sets the X509::Store to be used for verifying peer certificate.
- # - {:ciphers}[rdoc-ref:Net::HTTP#ciphers]:
- # Returns the available SSL ciphers.
- # - {:ciphers=}[rdoc-ref:Net::HTTP#ciphers=]:
- # Sets the available SSL ciphers.
- # - {:extra_chain_cert}[rdoc-ref:Net::HTTP#extra_chain_cert]:
- # Returns the extra X509 certificates to be added to the certificate chain.
- # - {:extra_chain_cert=}[rdoc-ref:Net::HTTP#extra_chain_cert=]:
- # Sets the extra X509 certificates to be added to the certificate chain.
- # - {:key}[rdoc-ref:Net::HTTP#key]:
- # Returns the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
- # - {:key=}[rdoc-ref:Net::HTTP#key=]:
- # Sets the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
- # - {:max_version}[rdoc-ref:Net::HTTP#max_version]:
- # Returns the maximum SSL version.
- # - {:max_version=}[rdoc-ref:Net::HTTP#max_version=]:
- # Sets the maximum SSL version.
- # - {:min_version}[rdoc-ref:Net::HTTP#min_version]:
- # Returns the minimum SSL version.
- # - {:min_version=}[rdoc-ref:Net::HTTP#min_version=]:
- # Sets the minimum SSL version.
- # - {#peer_cert}[rdoc-ref:Net::HTTP#peer_cert]:
- # Returns the X509 certificate chain for the session's socket peer.
- # - {:ssl_version}[rdoc-ref:Net::HTTP#ssl_version]:
- # Returns the SSL version.
- # - {:ssl_version=}[rdoc-ref:Net::HTTP#ssl_version=]:
- # Sets the SSL version.
- # - {#use_ssl=}[rdoc-ref:Net::HTTP#use_ssl=]:
- # Sets whether a new session is to use Transport Layer Security.
- # - {#use_ssl?}[rdoc-ref:Net::HTTP#use_ssl?]:
- # Returns whether +self+ uses SSL.
- # - {:verify_callback}[rdoc-ref:Net::HTTP#verify_callback]:
- # Returns the callback for the server certification verification.
- # - {:verify_callback=}[rdoc-ref:Net::HTTP#verify_callback=]:
- # Sets the callback for the server certification verification.
- # - {:verify_depth}[rdoc-ref:Net::HTTP#verify_depth]:
- # Returns the maximum depth for the certificate chain verification.
- # - {:verify_depth=}[rdoc-ref:Net::HTTP#verify_depth=]:
- # Sets the maximum depth for the certificate chain verification.
- # - {:verify_hostname}[rdoc-ref:Net::HTTP#verify_hostname]:
- # Returns the flags for server the certification verification at the beginning of the SSL/TLS session.
- # - {:verify_hostname=}[rdoc-ref:Net::HTTP#verify_hostname=]:
- # Sets he flags for server the certification verification at the beginning of the SSL/TLS session.
- # - {:verify_mode}[rdoc-ref:Net::HTTP#verify_mode]:
- # Returns the flags for server the certification verification at the beginning of the SSL/TLS session.
- # - {:verify_mode=}[rdoc-ref:Net::HTTP#verify_mode=]:
- # Sets the flags for server the certification verification at the beginning of the SSL/TLS session.
- #
- # === Addresses and Ports
- #
- # - {:address}[rdoc-ref:Net::HTTP#address]:
- # Returns the string host name or host IP.
- # - {::default_port}[rdoc-ref:Net::HTTP.default_port]:
- # Returns integer 80, the default port to use for HTTP requests.
- # - {::http_default_port}[rdoc-ref:Net::HTTP.http_default_port]:
- # Returns integer 80, the default port to use for HTTP requests.
- # - {::https_default_port}[rdoc-ref:Net::HTTP.https_default_port]:
- # Returns integer 443, the default port to use for HTTPS requests.
- # - {#ipaddr}[rdoc-ref:Net::HTTP#ipaddr]:
- # Returns the IP address for the connection.
- # - {#ipaddr=}[rdoc-ref:Net::HTTP#ipaddr=]:
- # Sets the IP address for the connection.
- # - {:local_host}[rdoc-ref:Net::HTTP#local_host]:
- # Returns the string local host used to establish the connection.
- # - {:local_host=}[rdoc-ref:Net::HTTP#local_host=]:
- # Sets the string local host used to establish the connection.
- # - {:local_port}[rdoc-ref:Net::HTTP#local_port]:
- # Returns the integer local port used to establish the connection.
- # - {:local_port=}[rdoc-ref:Net::HTTP#local_port=]:
- # Sets the integer local port used to establish the connection.
- # - {:port}[rdoc-ref:Net::HTTP#port]:
- # Returns the integer port number.
- #
- # === \HTTP Version
- #
- # - {::version_1_2?}[rdoc-ref:Net::HTTP.version_1_2?]
- # (aliased as {::is_version_1_2?}[rdoc-ref:Net::HTTP.is_version_1_2?]
- # and {::version_1_2}[rdoc-ref:Net::HTTP.version_1_2]):
- # Returns true; retained for compatibility.
- #
- # === Debugging
- #
- # - {#set_debug_output}[rdoc-ref:Net::HTTP#set_debug_output]:
- # Sets the output stream for debugging.
+ # Compression can be disabled through the Accept-Encoding: identity header.
#
class HTTP < Protocol
# :stopdoc:
- VERSION = "0.4.1"
+ VERSION = "0.3.2"
+ Revision = %q$Revision$.split[1]
HTTPVersion = '1.1'
begin
require 'zlib'
@@ -890,10 +548,10 @@ module Net #:nodoc:
end
#
- # \HTTP session management
+ # HTTP session management
#
- # Returns integer +80+, the default port to use for \HTTP requests:
+ # Returns intger +80+, the default port to use for HTTP requests:
#
# Net::HTTP.default_port # => 80
#
@@ -901,7 +559,7 @@ module Net #:nodoc:
http_default_port()
end
- # Returns integer +80+, the default port to use for \HTTP requests:
+ # Returns integer +80+, the default port to use for HTTP requests:
#
# Net::HTTP.http_default_port # => 80
#
@@ -927,11 +585,14 @@ module Net #:nodoc:
#
# Creates a new \Net::HTTP object, +http+, via \Net::HTTP.new:
#
- # - For arguments +address+ and +port+, see Net::HTTP.new.
- # - For proxy-defining arguments +p_addr+ through +p_pass+,
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
+ # Net::HTTP.new(address, port, p_addr, p_port, p_user, p_pass)
+ #
+ # - For arguments +hostname+ through +p_pass+, see Net::HTTP.new.
# - For argument +opts+, see below.
#
+ # Note: If +port+ is +nil+ and <tt>opts[:use_ssl]</tt> is a truthy value,
+ # the value passed to +new+ is Net::HTTP.https_default_port, not +port+.
+ #
# With no block given:
#
# - Calls <tt>http.start</tt> with no block (see #start),
@@ -1004,9 +665,6 @@ module Net #:nodoc:
# - #verify_mode
# - #write_timeout
#
- # Note: If +port+ is +nil+ and <tt>opts[:use_ssl]</tt> is a truthy value,
- # the value passed to +new+ is Net::HTTP.https_default_port, not +port+.
- #
def HTTP.start(address, *arg, &block) # :yield: +http+
arg.pop if opt = Hash.try_convert(arg[-1])
port, p_addr, p_port, p_user, p_pass = *arg
@@ -1033,10 +691,12 @@ module Net #:nodoc:
alias newobj new # :nodoc:
end
- # Returns a new \Net::HTTP object +http+
- # (but does not open a TCP connection or \HTTP session).
+ # Returns a new Net::HTTP object +http+
+ # (but does not open a TCP connection or HTTP session).
+ #
+ # <b>No Proxy</b>
#
- # With only string argument +address+ given
+ # With only string argument +hostname+ given
# (and <tt>ENV['http_proxy']</tt> undefined or +nil+),
# the returned +http+:
#
@@ -1059,8 +719,85 @@ module Net #:nodoc:
# # => #<Net::HTTP jsonplaceholder.typicode.com:8000 open=false>
# http.port # => 8000
#
- # For proxy-defining arguments +p_addr+ through +p_no_proxy+,
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
+ # <b>Proxy Using Argument +p_addr+ as a \String</b>
+ #
+ # When argument +p_addr+ is a string hostname,
+ # the returned +http+ has a proxy:
+ #
+ # http = Net::HTTP.new(hostname, nil, 'proxy.example')
+ # # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>
+ # http.proxy? # => true
+ # http.proxy_address # => "proxy.example"
+ # # These use default values.
+ # http.proxy_port # => 80
+ # http.proxy_user # => nil
+ # http.proxy_pass # => nil
+ #
+ # The port, username, and password for the proxy may also be given:
+ #
+ # http = Net::HTTP.new(hostname, nil, 'proxy.example', 8000, 'pname', 'ppass')
+ # # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>
+ # http.proxy? # => true
+ # http.proxy_address # => "proxy.example"
+ # http.proxy_port # => 8000
+ # http.proxy_user # => "pname"
+ # http.proxy_pass # => "ppass"
+ #
+ # <b>Proxy Using <tt>ENV['http_proxy']</tt></b>
+ #
+ # When environment variable <tt>'http_proxy'</tt>
+ # is set to a \URI string,
+ # the returned +http+ will have that URI as its proxy;
+ # note that the \URI string must have a protocol
+ # such as <tt>'http'</tt> or <tt>'https'</tt>:
+ #
+ # ENV['http_proxy'] = 'http://example.com'
+ # # => "http://example.com"
+ # http = Net::HTTP.new(hostname)
+ # # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>
+ # http.proxy? # => true
+ # http.address # => "jsonplaceholder.typicode.com"
+ # http.proxy_address # => "example.com"
+ #
+ # The \URI string may include proxy username, password, and port number:
+ #
+ # ENV['http_proxy'] = 'http://pname:ppass@example.com:8000'
+ # # => "http://pname:ppass@example.com:8000"
+ # http = Net::HTTP.new(hostname)
+ # # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>
+ # http.proxy_port # => 8000
+ # http.proxy_user # => "pname"
+ # http.proxy_pass # => "ppass"
+ #
+ # <b>Argument +p_no_proxy+</b>
+ #
+ # You can use argument +p_no_proxy+ to reject certain proxies:
+ #
+ # - Reject a certain address:
+ #
+ # http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example')
+ # http.proxy_address # => nil
+ #
+ # - Reject certain domains or subdomains:
+ #
+ # http = Net::HTTP.new('example.com', nil, 'my.proxy.example', 8000, 'pname', 'ppass', 'proxy.example')
+ # http.proxy_address # => nil
+ #
+ # - Reject certain addresses and port combinations:
+ #
+ # http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:1234')
+ # http.proxy_address # => "proxy.example"
+ #
+ # http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:8000')
+ # http.proxy_address # => nil
+ #
+ # - Reject a list of the types above delimited using a comma:
+ #
+ # http = Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000')
+ # http.proxy_address # => nil
+ #
+ # http = Net::HTTP.new('example.com', nil, 'my.proxy', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000')
+ # http.proxy_address # => nil
#
def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil)
http = super address, port
@@ -1074,7 +811,7 @@ module Net #:nodoc:
elsif p_addr == :ENV then
http.proxy_from_env = true
else
- if p_addr && p_no_proxy && !URI::Generic.use_proxy?(address, address, port, p_no_proxy)
+ if p_addr && p_no_proxy && !URI::Generic.use_proxy?(p_addr, p_addr, p_port, p_no_proxy)
p_addr = nil
p_port = nil
end
@@ -1087,10 +824,10 @@ module Net #:nodoc:
http
end
- # Creates a new \Net::HTTP object for the specified server address,
- # without opening the TCP connection or initializing the \HTTP session.
+ # Creates a new Net::HTTP object for the specified server address,
+ # without opening the TCP connection or initializing the HTTP session.
# The +address+ should be a DNS hostname or IP address.
- def initialize(address, port = nil) # :nodoc:
+ def initialize(address, port = nil)
@address = address
@port = (port || HTTP.default_port)
@ipaddr = nil
@@ -1190,22 +927,21 @@ module Net #:nodoc:
@debug_output = output
end
- # Returns the string host name or host IP given as argument +address+ in ::new.
+ # The DNS host name or IP address to connect to.
attr_reader :address
- # Returns the integer port number given as argument +port+ in ::new.
+ # The port number to connect to.
attr_reader :port
- # Sets or returns the string local host used to establish the connection;
- # initially +nil+.
+ # The local host used to establish the connection.
attr_accessor :local_host
- # Sets or returns the integer local port used to establish the connection;
- # initially +nil+.
+ # The local port used to establish the connection.
attr_accessor :local_port
- # Returns the encoding to use for the response body;
- # see #response_body_encoding=.
+ # The encoding to use for the response body. If Encoding, uses the
+ # specified encoding. If other true value, tries to detect the response
+ # body encoding.
attr_reader :response_body_encoding
# Sets the encoding to be used for the response body;
@@ -1231,25 +967,10 @@ module Net #:nodoc:
@response_body_encoding = value
end
- # Sets whether to determine the proxy from environment variable
- # '<tt>ENV['http_proxy']</tt>';
- # see {Proxy Using ENV['http_proxy']}[rdoc-ref:Net::HTTP@Proxy+Using+-27ENV-5B-27http_proxy-27-5D-27].
attr_writer :proxy_from_env
-
- # Sets the proxy address;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
attr_writer :proxy_address
-
- # Sets the proxy port;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
attr_writer :proxy_port
-
- # Sets the proxy user;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
attr_writer :proxy_user
-
- # Sets the proxy password;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
attr_writer :proxy_pass
# Returns the IP address for the connection.
@@ -1288,25 +1009,27 @@ module Net #:nodoc:
@ipaddr = addr
end
- # Sets or returns the numeric (\Integer or \Float) number of seconds
- # to wait for a connection to open;
- # initially 60.
- # If the connection is not made in the given interval,
- # an exception is raised.
+ # Number of seconds to wait for the connection to open. Any number
+ # may be used, including Floats for fractional seconds. If the HTTP
+ # object cannot open a connection in this many seconds, it raises a
+ # Net::OpenTimeout exception. The default value is 60 seconds.
attr_accessor :open_timeout
- # Returns the numeric (\Integer or \Float) number of seconds
- # to wait for one block to be read (via one read(2) call);
- # see #read_timeout=.
+ # Number of seconds to wait for one block to be read (via one read(2)
+ # call). Any number may be used, including Floats for fractional
+ # seconds. If the HTTP object cannot read data in this many seconds,
+ # it raises a Net::ReadTimeout exception. The default value is 60 seconds.
attr_reader :read_timeout
- # Returns the numeric (\Integer or \Float) number of seconds
- # to wait for one block to be written (via one write(2) call);
- # see #write_timeout=.
+ # Number of seconds to wait for one block to be written (via one write(2)
+ # call). Any number may be used, including Floats for fractional
+ # seconds. If the HTTP object cannot write data in this many seconds,
+ # it raises a Net::WriteTimeout exception. The default value is 60 seconds.
+ # Net::WriteTimeout is not raised on Windows.
attr_reader :write_timeout
# Sets the maximum number of times to retry an idempotent request in case of
- # \Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET,
+ # Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET,
# Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL::SSLError,
# Timeout::Error.
# The initial value is 1.
@@ -1325,8 +1048,6 @@ module Net #:nodoc:
@max_retries = retries
end
- # Returns the maximum number of times to retry an idempotent request;
- # see #max_retries=.
attr_reader :max_retries
# Sets the read timeout, in seconds, for +self+ to integer +sec+;
@@ -1348,90 +1069,52 @@ module Net #:nodoc:
# Sets the write timeout, in seconds, for +self+ to integer +sec+;
# the initial value is 60.
#
- # Argument +sec+ must be a non-negative numeric value:
- #
- # _uri = uri.dup
- # _uri.path = '/posts'
- # body = 'bar' * 200000
- # data = <<EOF
- # {"title": "foo", "body": "#{body}", "userId": "1"}
- # EOF
- # headers = {'content-type': 'application/json'}
- # http = Net::HTTP.new(hostname)
- # http.write_timeout # => 60
- # http.post(_uri.path, data, headers)
- # # => #<Net::HTTPCreated 201 Created readbody=true>
- # http.write_timeout = 0
- # http.post(_uri.path, data, headers) # Raises Net::WriteTimeout.
+ # Argument +sec+ must be a non-negative numeric value.
#
def write_timeout=(sec)
@socket.write_timeout = sec if @socket
@write_timeout = sec
end
- # Returns the continue timeout value;
- # see continue_timeout=.
+ # Seconds to wait for 100 Continue response. If the HTTP object does not
+ # receive a response in this many seconds it sends the request body. The
+ # default value is +nil+.
attr_reader :continue_timeout
- # Sets the continue timeout value,
- # which is the number of seconds to wait for an expected 100 Continue response.
- # If the \HTTP object does not receive a response in this many seconds
- # it sends the request body.
+ # Setter for the continue_timeout attribute.
def continue_timeout=(sec)
@socket.continue_timeout = sec if @socket
@continue_timeout = sec
end
- # Sets or returns the numeric (\Integer or \Float) number of seconds
- # to keep the connection open after a request is sent;
- # initially 2.
- # If a new request is made during the given interval,
- # the still-open connection is used;
- # otherwise the connection will have been closed
- # and a new connection is opened.
+ # Seconds to reuse the connection of the previous request.
+ # If the idle time is less than this Keep-Alive Timeout,
+ # Net::HTTP reuses the TCP/IP socket used by the previous communication.
+ # The default value is 2 seconds.
attr_accessor :keep_alive_timeout
- # Sets or returns whether to ignore end-of-file when reading a response body
- # with <tt>Content-Length</tt> headers;
- # initially +true+.
+ # Whether to ignore EOF when reading response bodies with defined
+ # Content-Length headers. For backwards compatibility, the default is true.
attr_accessor :ignore_eof
- # Returns +true+ if the \HTTP session has been started:
- #
- # http = Net::HTTP.new(hostname)
- # http.started? # => false
- # http.start
- # http.started? # => true
- # http.finish # => nil
- # http.started? # => false
- #
- # Net::HTTP.start(hostname) do |http|
- # http.started?
- # end # => true
- # http.started? # => false
- #
+ # Returns true if the HTTP session has been started.
def started?
@started
end
alias active? started? #:nodoc: obsolete
- # Sets or returns whether to close the connection when the response is empty;
- # initially +false+.
attr_accessor :close_on_empty_response
- # Returns +true+ if +self+ uses SSL, +false+ otherwise.
- # See Net::HTTP#use_ssl=.
+ # Returns true if SSL/TLS is being used with HTTP.
def use_ssl?
@use_ssl
end
- # Sets whether a new session is to use
- # {Transport Layer Security}[https://en.wikipedia.org/wiki/Transport_Layer_Security]:
- #
- # Raises IOError if attempting to change during a session.
- #
- # Raises OpenSSL::SSL::SSLError if the port is not an HTTPS port.
+ # Turn on/off SSL.
+ # This flag must be set before starting session.
+ # If you change use_ssl value after session started,
+ # a Net::HTTP object raises IOError.
def use_ssl=(flag)
flag = flag ? true : false
if started? and @use_ssl != flag
@@ -1456,7 +1139,7 @@ module Net #:nodoc:
:@verify_depth,
:@verify_mode,
:@verify_hostname,
- ] # :nodoc:
+ ]
SSL_ATTRIBUTES = [
:ca_file,
:ca_path,
@@ -1473,67 +1156,64 @@ module Net #:nodoc:
:verify_depth,
:verify_mode,
:verify_hostname,
- ] # :nodoc:
+ ]
- # Sets or returns the path to a CA certification file in PEM format.
+ # Sets path of a CA certification file in PEM format.
+ #
+ # The file can contain several CA certificates.
attr_accessor :ca_file
- # Sets or returns the path of to CA directory
- # containing certification files in PEM format.
+ # Sets path of a CA certification directory containing certifications in
+ # PEM format.
attr_accessor :ca_path
- # Sets or returns the OpenSSL::X509::Certificate object
- # to be used for client certification.
+ # Sets an OpenSSL::X509::Certificate object as client certificate.
+ # (This method is appeared in Michal Rokos's OpenSSL extension).
attr_accessor :cert
- # Sets or returns the X509::Store to be used for verifying peer certificate.
+ # Sets the X509::Store to verify peer certificate.
attr_accessor :cert_store
- # Sets or returns the available SSL ciphers.
- # See {OpenSSL::SSL::SSLContext#ciphers=}[rdoc-ref:OpenSSL::SSL::SSLContext#ciphers-3D].
+ # Sets the available ciphers. See OpenSSL::SSL::SSLContext#ciphers=
attr_accessor :ciphers
- # Sets or returns the extra X509 certificates to be added to the certificate chain.
- # See {OpenSSL::SSL::SSLContext#add_certificate}[rdoc-ref:OpenSSL::SSL::SSLContext#add_certificate].
+ # Sets the extra X509 certificates to be added to the certificate chain.
+ # See OpenSSL::SSL::SSLContext#extra_chain_cert=
attr_accessor :extra_chain_cert
- # Sets or returns the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
+ # Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
+ # (This method is appeared in Michal Rokos's OpenSSL extension.)
attr_accessor :key
- # Sets or returns the SSL timeout seconds.
+ # Sets the SSL timeout seconds.
attr_accessor :ssl_timeout
- # Sets or returns the SSL version.
- # See {OpenSSL::SSL::SSLContext#ssl_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#ssl_version-3D].
+ # Sets the SSL version. See OpenSSL::SSL::SSLContext#ssl_version=
attr_accessor :ssl_version
- # Sets or returns the minimum SSL version.
- # See {OpenSSL::SSL::SSLContext#min_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#min_version-3D].
+ # Sets the minimum SSL version. See OpenSSL::SSL::SSLContext#min_version=
attr_accessor :min_version
- # Sets or returns the maximum SSL version.
- # See {OpenSSL::SSL::SSLContext#max_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#max_version-3D].
+ # Sets the maximum SSL version. See OpenSSL::SSL::SSLContext#max_version=
attr_accessor :max_version
- # Sets or returns the callback for the server certification verification.
+ # Sets the verify callback for the server certification verification.
attr_accessor :verify_callback
- # Sets or returns the maximum depth for the certificate chain verification.
+ # Sets the maximum depth for the certificate chain verification.
attr_accessor :verify_depth
- # Sets or returns the flags for server the certification verification
- # at the beginning of the SSL/TLS session.
+ # Sets the flags for server the certification verification at beginning of
+ # SSL/TLS session.
+ #
# OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER are acceptable.
attr_accessor :verify_mode
- # Sets or returns whether to verify that the server certificate is valid
- # for the hostname.
- # See {OpenSSL::SSL::SSLContext#verify_hostname=}[rdoc-ref:OpenSSL::SSL::SSLContext#attribute-i-verify_mode].
+ # Sets to check the server certificate is valid for the hostname.
+ # See OpenSSL::SSL::SSLContext#verify_hostname=
attr_accessor :verify_hostname
- # Returns the X509 certificate chain (an array of strings)
- # for the session's socket peer,
- # or +nil+ if none.
+ # Returns the X.509 certificates the server presented.
def peer_cert
if not use_ssl? or not @socket
return nil
@@ -1541,26 +1221,14 @@ module Net #:nodoc:
@socket.io.peer_cert
end
- # Starts an \HTTP session.
- #
- # Without a block, returns +self+:
+ # Opens a TCP connection and HTTP session.
#
- # http = Net::HTTP.new(hostname)
- # # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.start
- # # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=true>
- # http.started? # => true
- # http.finish
- #
- # With a block, calls the block with +self+,
- # finishes the session when the block exits,
- # and returns the block's value:
+ # When this method is called with a block, it passes the Net::HTTP
+ # object to the block, and closes the TCP connection and HTTP session
+ # after the block has been executed.
#
- # http.start do |http|
- # http
- # end
- # # => #<Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.started? # => false
+ # When called with a block, it returns the return value of the
+ # block; otherwise, it returns self.
#
def start # :yield: http
raise IOError, 'HTTP session already opened' if @started
@@ -1614,8 +1282,8 @@ module Net #:nodoc:
write_timeout: @write_timeout,
continue_timeout: @continue_timeout,
debug_output: @debug_output)
- buf = +"CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n" \
- "Host: #{@address}:#{@port}\r\n"
+ buf = "CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n"
+ buf << "Host: #{@address}:#{@port}\r\n"
if proxy_user
credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0')
buf << "Proxy-Authorization: Basic #{credential}\r\n"
@@ -1696,15 +1364,8 @@ module Net #:nodoc:
end
private :on_connect
- # Finishes the \HTTP session:
- #
- # http = Net::HTTP.new(hostname)
- # http.start
- # http.started? # => true
- # http.finish # => nil
- # http.started? # => false
- #
- # Raises IOError if not in a session.
+ # Finishes the HTTP session and closes the TCP connection.
+ # Raises IOError if the session has not been started.
def finish
raise IOError, 'HTTP session not yet started' unless started?
do_finish
@@ -1731,11 +1392,11 @@ module Net #:nodoc:
@proxy_user = nil
@proxy_pass = nil
- # Creates an \HTTP proxy class which behaves like \Net::HTTP, but
+ # Creates an HTTP proxy class which behaves like Net::HTTP, but
# performs all access via the specified proxy.
#
# This class is obsolete. You may pass these same parameters directly to
- # \Net::HTTP.new. See Net::HTTP.new for details of the arguments.
+ # Net::HTTP.new. See Net::HTTP.new for details of the arguments.
def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil) #:nodoc:
return self unless p_addr
@@ -1758,37 +1419,31 @@ module Net #:nodoc:
end
class << HTTP
- # Returns true if self is a class which was created by HTTP::Proxy.
+ # returns true if self is a class which was created by HTTP::Proxy.
def proxy_class?
defined?(@is_proxy_class) ? @is_proxy_class : false
end
- # Returns the address of the proxy host, or +nil+ if none;
- # see Net::HTTP@Proxy+Server.
+ # Address of proxy host. If Net::HTTP does not use a proxy, nil.
attr_reader :proxy_address
- # Returns the port number of the proxy host, or +nil+ if none;
- # see Net::HTTP@Proxy+Server.
+ # Port number of proxy host. If Net::HTTP does not use a proxy, nil.
attr_reader :proxy_port
- # Returns the user name for accessing the proxy, or +nil+ if none;
- # see Net::HTTP@Proxy+Server.
+ # User name for accessing proxy. If Net::HTTP does not use a proxy, nil.
attr_reader :proxy_user
- # Returns the password for accessing the proxy, or +nil+ if none;
- # see Net::HTTP@Proxy+Server.
+ # User password for accessing proxy. If Net::HTTP does not use a proxy,
+ # nil.
attr_reader :proxy_pass
end
- # Returns +true+ if a proxy server is defined, +false+ otherwise;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
+ # True if requests for this connection will be proxied
def proxy?
!!(@proxy_from_env ? proxy_uri : @proxy_address)
end
- # Returns +true+ if the proxy server is defined in the environment,
- # +false+ otherwise;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
+ # True if the proxy for this connection is determined from the environment
def proxy_from_env?
@proxy_from_env
end
@@ -1797,13 +1452,12 @@ module Net #:nodoc:
def proxy_uri # :nodoc:
return if @proxy_uri == false
@proxy_uri ||= URI::HTTP.new(
- "http", nil, address, port, nil, nil, nil, nil, nil
+ "http".freeze, nil, address, port, nil, nil, nil, nil, nil
).find_proxy || false
@proxy_uri || nil
end
- # Returns the address of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
+ # The address of the proxy server, if one is configured.
def proxy_address
if @proxy_from_env then
proxy_uri&.hostname
@@ -1812,8 +1466,7 @@ module Net #:nodoc:
end
end
- # Returns the port number of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
+ # The port of the proxy server, if one is configured.
def proxy_port
if @proxy_from_env then
proxy_uri&.port
@@ -1822,8 +1475,7 @@ module Net #:nodoc:
end
end
- # Returns the user name of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
+ # The username of the proxy server, if one is configured.
def proxy_user
if @proxy_from_env
user = proxy_uri&.user
@@ -1833,8 +1485,7 @@ module Net #:nodoc:
end
end
- # Returns the password of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
+ # The password of the proxy server, if one is configured.
def proxy_pass
if @proxy_from_env
pass = proxy_uri&.password
@@ -1882,38 +1533,45 @@ module Net #:nodoc:
public
- # :call-seq:
- # get(path, initheader = nil) {|res| ... }
+ # Retrieves data from +path+ on the connected-to host which may be an
+ # absolute path String or a URI to extract the path from.
#
- # Sends a GET request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
+ # +initheader+ must be a Hash like { 'Accept' => '*/*', ... },
+ # and it defaults to an empty hash.
+ # If +initheader+ doesn't have the key 'accept-encoding', then
+ # a value of "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" is used,
+ # so that gzip compression is used in preference to deflate
+ # compression, which is used in preference to no compression.
+ # Ruby doesn't have libraries to support the compress (Lempel-Ziv)
+ # compression, so that is not supported. The intent of this is
+ # to reduce bandwidth by default. If this routine sets up
+ # compression, then it does the decompression also, removing
+ # the header as well to prevent confusion. Otherwise
+ # it leaves the body as it found it.
#
- # The request is based on the Net::HTTP::Get object
- # created from string +path+ and initial headers hash +initheader+.
+ # This method returns a Net::HTTPResponse object.
#
- # With a block given, calls the block with the response body:
+ # If called with a block, yields each fragment of the
+ # entity body in turn as a string as it is read from
+ # the socket. Note that in this case, the returned response
+ # object will *not* contain a (meaningful) body.
#
- # http = Net::HTTP.new(hostname)
- # http.get('/todos/1') do |res|
- # p res
- # end # => #<Net::HTTPOK 200 OK readbody=true>
+ # +dest+ argument is obsolete.
+ # It still works but you must not use it.
#
- # Output:
- #
- # "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n}"
- #
- # With no block given, simply returns the response object:
+ # This method never raises an exception.
#
- # http.get('/') # => #<Net::HTTPOK 200 OK readbody=true>
+ # response = http.get('/index.html')
#
- # Related:
- #
- # - Net::HTTP::Get: request class for \HTTP method GET.
- # - Net::HTTP.get: sends GET request, returns response body.
+ # # using block
+ # File.open('result.txt', 'w') {|f|
+ # http.get('/~foo/') do |str|
+ # f.write str
+ # end
+ # }
#
def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
res = nil
-
request(Get.new(path, initheader)) {|r|
r.read_body dest, &block
res = r
@@ -1921,312 +1579,198 @@ module Net #:nodoc:
res
end
- # Sends a HEAD request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
+ # Gets only the header from +path+ on the connected-to host.
+ # +header+ is a Hash like { 'Accept' => '*/*', ... }.
#
- # The request is based on the Net::HTTP::Head object
- # created from string +path+ and initial headers hash +initheader+:
+ # This method returns a Net::HTTPResponse object.
#
- # res = http.head('/todos/1') # => #<Net::HTTPOK 200 OK readbody=true>
- # res.body # => nil
- # res.to_hash.take(3)
- # # =>
- # [["date", ["Wed, 15 Feb 2023 15:25:42 GMT"]],
- # ["content-type", ["application/json; charset=utf-8"]],
- # ["connection", ["close"]]]
+ # This method never raises an exception.
+ #
+ # response = nil
+ # Net::HTTP.start('some.www.server', 80) {|http|
+ # response = http.head('/index.html')
+ # }
+ # p response['content-type']
#
def head(path, initheader = nil)
request(Head.new(path, initheader))
end
- # :call-seq:
- # post(path, data, initheader = nil) {|res| ... }
- #
- # Sends a POST request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
+ # Posts +data+ (must be a String) to +path+. +header+ must be a Hash
+ # like { 'Accept' => '*/*', ... }.
#
- # The request is based on the Net::HTTP::Post object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # With a block given, calls the block with the response body:
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Net::HTTP.new(hostname)
- # http.post('/todos', data) do |res|
- # p res
- # end # => #<Net::HTTPCreated 201 Created readbody=true>
+ # This method returns a Net::HTTPResponse object.
#
- # Output:
+ # If called with a block, yields each fragment of the
+ # entity body in turn as a string as it is read from
+ # the socket. Note that in this case, the returned response
+ # object will *not* contain a (meaningful) body.
#
- # "{\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\",\n \"id\": 201\n}"
+ # +dest+ argument is obsolete.
+ # It still works but you must not use it.
#
- # With no block given, simply returns the response object:
+ # This method never raises exception.
#
- # http.post('/todos', data) # => #<Net::HTTPCreated 201 Created readbody=true>
+ # response = http.post('/cgi-bin/search.rb', 'query=foo')
#
- # Related:
+ # # using block
+ # File.open('result.txt', 'w') {|f|
+ # http.post('/cgi-bin/search.rb', 'query=foo') do |str|
+ # f.write str
+ # end
+ # }
#
- # - Net::HTTP::Post: request class for \HTTP method POST.
- # - Net::HTTP.post: sends POST request, returns response body.
+ # You should set Content-Type: header field for POST.
+ # If no Content-Type: field given, this method uses
+ # "application/x-www-form-urlencoded" by default.
#
def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
send_entity(path, data, initheader, dest, Post, &block)
end
- # :call-seq:
- # patch(path, data, initheader = nil) {|res| ... }
- #
- # Sends a PATCH request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Patch object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # With a block given, calls the block with the response body:
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Net::HTTP.new(hostname)
- # http.patch('/todos/1', data) do |res|
- # p res
- # end # => #<Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false,\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\"\n}"
- #
- # With no block given, simply returns the response object:
- #
- # http.patch('/todos/1', data) # => #<Net::HTTPCreated 201 Created readbody=true>
- #
+ # Sends a PATCH request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
send_entity(path, data, initheader, dest, Patch, &block)
end
- # Sends a PUT request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Put object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Net::HTTP.new(hostname)
- # http.put('/todos/1', data) # => #<Net::HTTPOK 200 OK readbody=true>
- #
- def put(path, data, initheader = nil)
+ def put(path, data, initheader = nil) #:nodoc:
request(Put.new(path, initheader), data)
end
- # Sends a PROPPATCH request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Proppatch object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Net::HTTP.new(hostname)
- # http.proppatch('/todos/1', data)
- #
+ # Sends a PROPPATCH request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def proppatch(path, body, initheader = nil)
request(Proppatch.new(path, initheader), body)
end
- # Sends a LOCK request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Lock object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Net::HTTP.new(hostname)
- # http.lock('/todos/1', data)
- #
+ # Sends a LOCK request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def lock(path, body, initheader = nil)
request(Lock.new(path, initheader), body)
end
- # Sends an UNLOCK request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Unlock object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Net::HTTP.new(hostname)
- # http.unlock('/todos/1', data)
- #
+ # Sends a UNLOCK request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def unlock(path, body, initheader = nil)
request(Unlock.new(path, initheader), body)
end
- # Sends an Options request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Options object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Net::HTTP.new(hostname)
- # http.options('/')
- #
+ # Sends a OPTIONS request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def options(path, initheader = nil)
request(Options.new(path, initheader))
end
- # Sends a PROPFIND request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Propfind object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Net::HTTP.new(hostname)
- # http.propfind('/todos/1', data)
- #
+ # Sends a PROPFIND request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def propfind(path, body = nil, initheader = {'Depth' => '0'})
request(Propfind.new(path, initheader), body)
end
- # Sends a DELETE request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Delete object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Net::HTTP.new(hostname)
- # http.delete('/todos/1')
- #
+ # Sends a DELETE request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def delete(path, initheader = {'Depth' => 'Infinity'})
request(Delete.new(path, initheader))
end
- # Sends a MOVE request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Move object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Net::HTTP.new(hostname)
- # http.move('/todos/1')
- #
+ # Sends a MOVE request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def move(path, initheader = nil)
request(Move.new(path, initheader))
end
- # Sends a COPY request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Copy object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Net::HTTP.new(hostname)
- # http.copy('/todos/1')
- #
+ # Sends a COPY request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def copy(path, initheader = nil)
request(Copy.new(path, initheader))
end
- # Sends a MKCOL request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Mkcol object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http.mkcol('/todos/1', data)
- # http = Net::HTTP.new(hostname)
- #
+ # Sends a MKCOL request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def mkcol(path, body = nil, initheader = nil)
request(Mkcol.new(path, initheader), body)
end
- # Sends a TRACE request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Trace object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Net::HTTP.new(hostname)
- # http.trace('/todos/1')
- #
+ # Sends a TRACE request to the +path+ and gets a response,
+ # as an HTTPResponse object.
def trace(path, initheader = nil)
request(Trace.new(path, initheader))
end
- # Sends a GET request to the server;
- # forms the response into a Net::HTTPResponse object.
+ # Sends a GET request to the +path+.
+ # Returns the response as a Net::HTTPResponse object.
#
- # The request is based on the Net::HTTP::Get object
- # created from string +path+ and initial headers hash +initheader+.
+ # When called with a block, passes an HTTPResponse object to the block.
+ # The body of the response will not have been read yet;
+ # the block can process it using HTTPResponse#read_body,
+ # if desired.
#
- # With no block given, returns the response object:
+ # Returns the response.
#
- # http = Net::HTTP.new(hostname)
- # http.request_get('/todos') # => #<Net::HTTPOK 200 OK readbody=true>
+ # This method never raises Net::* exceptions.
#
- # With a block given, calls the block with the response object
- # and returns the response object:
+ # response = http.request_get('/index.html')
+ # # The entity body is already read in this case.
+ # p response['content-type']
+ # puts response.body
#
- # http.request_get('/todos') do |res|
- # p res
- # end # => #<Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # #<Net::HTTPOK 200 OK readbody=false>
+ # # Using a block
+ # http.request_get('/index.html') {|response|
+ # p response['content-type']
+ # response.read_body do |str| # read body now
+ # print str
+ # end
+ # }
#
def request_get(path, initheader = nil, &block) # :yield: +response+
request(Get.new(path, initheader), &block)
end
- # Sends a HEAD request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
+ # Sends a HEAD request to the +path+ and returns the response
+ # as a Net::HTTPResponse object.
#
- # The request is based on the Net::HTTP::Head object
- # created from string +path+ and initial headers hash +initheader+.
+ # Returns the response.
#
- # http = Net::HTTP.new(hostname)
- # http.head('/todos/1') # => #<Net::HTTPOK 200 OK readbody=true>
+ # This method never raises Net::* exceptions.
+ #
+ # response = http.request_head('/index.html')
+ # p response['content-type']
#
def request_head(path, initheader = nil, &block)
request(Head.new(path, initheader), &block)
end
- # Sends a POST request to the server;
- # forms the response into a Net::HTTPResponse object.
- #
- # The request is based on the Net::HTTP::Post object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
+ # Sends a POST request to the +path+.
#
- # With no block given, returns the response object:
+ # Returns the response as a Net::HTTPResponse object.
#
- # http = Net::HTTP.new(hostname)
- # http.post('/todos', 'xyzzy')
- # # => #<Net::HTTPCreated 201 Created readbody=true>
+ # When called with a block, the block is passed an HTTPResponse
+ # object. The body of that response will not have been read yet;
+ # the block can process it using HTTPResponse#read_body, if desired.
#
- # With a block given, calls the block with the response body
- # and returns the response object:
+ # Returns the response.
#
- # http.post('/todos', 'xyzzy') do |res|
- # p res
- # end # => #<Net::HTTPCreated 201 Created readbody=true>
+ # This method never raises Net::* exceptions.
#
- # Output:
+ # # example
+ # response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
+ # p response.status
+ # puts response.body # body is already read in this case
#
- # "{\n \"xyzzy\": \"\",\n \"id\": 201\n}"
+ # # using block
+ # http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response|
+ # p response.status
+ # p response['content-type']
+ # response.read_body do |str| # read body now
+ # print str
+ # end
+ # }
#
def request_post(path, data, initheader = nil, &block) # :yield: +response+
request Post.new(path, initheader), data, &block
end
- # Sends a PUT request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
- #
- # The request is based on the Net::HTTP::Put object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # http = Net::HTTP.new(hostname)
- # http.put('/todos/1', 'xyzzy')
- # # => #<Net::HTTPOK 200 OK readbody=true>
- #
def request_put(path, data, initheader = nil, &block) #:nodoc:
request Put.new(path, initheader), data, &block
end
@@ -2236,25 +1780,16 @@ module Net #:nodoc:
alias post2 request_post #:nodoc: obsolete
alias put2 request_put #:nodoc: obsolete
- # Sends an \HTTP request to the server;
- # returns an instance of a subclass of Net::HTTPResponse.
+
+ # Sends an HTTP request to the HTTP server.
+ # Also sends a DATA string if +data+ is given.
#
- # The request is based on the Net::HTTPRequest object
- # created from string +path+, string +data+, and initial headers hash +header+.
- # That object is an instance of the
- # {subclass of Net::HTTPRequest}[rdoc-ref:Net::HTTPRequest@Request+Subclasses],
- # that corresponds to the given uppercase string +name+,
- # which must be
- # an {HTTP request method}[https://en.wikipedia.org/wiki/HTTP#Request_methods]
- # or a {WebDAV request method}[https://en.wikipedia.org/wiki/WebDAV#Implementation].
+ # Returns a Net::HTTPResponse object.
#
- # Examples:
+ # This method never raises Net::* exceptions.
#
- # http = Net::HTTP.new(hostname)
- # http.send_request('GET', '/todos/1')
- # # => #<Net::HTTPOK 200 OK readbody=true>
- # http.send_request('POST', '/todos', 'xyzzy')
- # # => #<Net::HTTPCreated 201 Created readbody=true>
+ # response = http.send_request('GET', '/index.html')
+ # puts response.body
#
def send_request(name, path, data = nil, header = nil)
has_response_body = name != 'HEAD'
@@ -2262,35 +1797,20 @@ module Net #:nodoc:
request r, data
end
- # Sends the given request +req+ to the server;
- # forms the response into a Net::HTTPResponse object.
- #
- # The given +req+ must be an instance of a
- # {subclass of Net::HTTPRequest}[rdoc-ref:Net::HTTPRequest@Request+Subclasses].
- # Argument +body+ should be given only if needed for the request.
+ # Sends an HTTPRequest object +req+ to the HTTP server.
#
- # With no block given, returns the response object:
+ # If +req+ is a Net::HTTP::Post or Net::HTTP::Put request containing
+ # data, the data is also sent. Providing data for a Net::HTTP::Head or
+ # Net::HTTP::Get request results in an ArgumentError.
#
- # http = Net::HTTP.new(hostname)
- #
- # req = Net::HTTP::Get.new('/todos/1')
- # http.request(req)
- # # => #<Net::HTTPOK 200 OK readbody=true>
- #
- # req = Net::HTTP::Post.new('/todos')
- # http.request(req, 'xyzzy')
- # # => #<Net::HTTPCreated 201 Created readbody=true>
+ # Returns an HTTPResponse object.
#
- # With a block given, calls the block with the response and returns the response:
- #
- # req = Net::HTTP::Get.new('/todos/1')
- # http.request(req) do |res|
- # p res
- # end # => #<Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
+ # When called with a block, passes an HTTPResponse object to the block.
+ # The body of the response will not have been read yet;
+ # the block can process it using HTTPResponse#read_body,
+ # if desired.
#
- # #<Net::HTTPOK 200 OK readbody=false>
+ # This method never raises Net::* exceptions.
#
def request(req, body = nil, &block) # :yield: +response+
unless started?
diff --git a/lib/net/http/backward.rb b/lib/net/http/backward.rb
index b44577edbd..691e41e4f1 100644
--- a/lib/net/http/backward.rb
+++ b/lib/net/http/backward.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
# for backward compatibility
# :enddoc:
diff --git a/lib/net/http/exceptions.rb b/lib/net/http/exceptions.rb
index ceec8f7b0a..9c425cae16 100644
--- a/lib/net/http/exceptions.rb
+++ b/lib/net/http/exceptions.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
module Net
# Net::HTTP exception class.
# You cannot use Net::HTTPExceptions directly; instead, you must use
diff --git a/lib/net/http/generic_request.rb b/lib/net/http/generic_request.rb
index 44e329a0c8..d56835c76f 100644
--- a/lib/net/http/generic_request.rb
+++ b/lib/net/http/generic_request.rb
@@ -1,18 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
+# HTTPGenericRequest is the parent of the Net::HTTPRequest class.
+# Do not use this directly; use a subclass of Net::HTTPRequest.
#
-# \HTTPGenericRequest is the parent of the Net::HTTPRequest class.
-#
-# Do not use this directly; instead, use a subclass of Net::HTTPRequest.
-#
-# == About the Examples
-#
-# :include: doc/net-http/examples.rdoc
+# Mixes in the Net::HTTPHeader module to provide easier access to HTTP headers.
#
class Net::HTTPGenericRequest
include Net::HTTPHeader
- def initialize(m, reqbody, resbody, uri_or_path, initheader = nil) # :nodoc:
+ def initialize(m, reqbody, resbody, uri_or_path, initheader = nil)
@method = m
@request_has_body = reqbody
@response_has_body = resbody
@@ -23,7 +19,7 @@ class Net::HTTPGenericRequest
raise ArgumentError, "no host component for URI" unless (hostname && hostname.length > 0)
@uri = uri_or_path.dup
host = @uri.hostname.dup
- host << ":" << @uri.port.to_s if @uri.port != @uri.default_port
+ host << ":".freeze << @uri.port.to_s if @uri.port != @uri.default_port
@path = uri_or_path.request_uri
raise ArgumentError, "no HTTP request path given" unless @path
else
@@ -57,47 +53,15 @@ class Net::HTTPGenericRequest
@body_data = nil
end
- # Returns the string method name for the request:
- #
- # Net::HTTP::Get.new(uri).method # => "GET"
- # Net::HTTP::Post.new(uri).method # => "POST"
- #
attr_reader :method
-
- # Returns the string path for the request:
- #
- # Net::HTTP::Get.new(uri).path # => "/"
- # Net::HTTP::Post.new('example.com').path # => "example.com"
- #
attr_reader :path
-
- # Returns the URI object for the request, or +nil+ if none:
- #
- # Net::HTTP::Get.new(uri).uri
- # # => #<URI::HTTPS https://jsonplaceholder.typicode.com/>
- # Net::HTTP::Get.new('example.com').uri # => nil
- #
attr_reader :uri
- # Returns +false+ if the request's header <tt>'Accept-Encoding'</tt>
- # has been set manually or deleted
- # (indicating that the user intends to handle encoding in the response),
- # +true+ otherwise:
- #
- # req = Net::HTTP::Get.new(uri) # => #<Net::HTTP::Get GET>
- # req['Accept-Encoding'] # => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
- # req.decode_content # => true
- # req['Accept-Encoding'] = 'foo'
- # req.decode_content # => false
- # req.delete('Accept-Encoding')
- # req.decode_content # => false
- #
+ # Automatically set to false if the user sets the Accept-Encoding header.
+ # This indicates they wish to handle Content-encoding in responses
+ # themselves.
attr_reader :decode_content
- # Returns a string representation of the request:
- #
- # Net::HTTP::Post.new(uri).inspect # => "#<Net::HTTP::Post POST>"
- #
def inspect
"\#<#{self.class} #{@method}>"
end
@@ -112,45 +76,21 @@ class Net::HTTPGenericRequest
super key, val
end
- # Returns whether the request may have a body:
- #
- # Net::HTTP::Post.new(uri).request_body_permitted? # => true
- # Net::HTTP::Get.new(uri).request_body_permitted? # => false
- #
def request_body_permitted?
@request_has_body
end
- # Returns whether the response may have a body:
- #
- # Net::HTTP::Post.new(uri).response_body_permitted? # => true
- # Net::HTTP::Head.new(uri).response_body_permitted? # => false
- #
def response_body_permitted?
@response_has_body
end
- def body_exist? # :nodoc:
+ def body_exist?
warn "Net::HTTPRequest#body_exist? is obsolete; use response_body_permitted?", uplevel: 1 if $VERBOSE
response_body_permitted?
end
- # Returns the string body for the request, or +nil+ if there is none:
- #
- # req = Net::HTTP::Post.new(uri)
- # req.body # => nil
- # req.body = '{"title": "foo","body": "bar","userId": 1}'
- # req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"
- #
attr_reader :body
- # Sets the body for the request:
- #
- # req = Net::HTTP::Post.new(uri)
- # req.body # => nil
- # req.body = '{"title": "foo","body": "bar","userId": 1}'
- # req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"
- #
def body=(str)
@body = str
@body_stream = nil
@@ -158,24 +98,8 @@ class Net::HTTPGenericRequest
str
end
- # Returns the body stream object for the request, or +nil+ if there is none:
- #
- # req = Net::HTTP::Post.new(uri) # => #<Net::HTTP::Post POST>
- # req.body_stream # => nil
- # require 'stringio'
- # req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8>
- # req.body_stream # => #<StringIO:0x0000027d1e5affa8>
- #
attr_reader :body_stream
- # Sets the body stream for the request:
- #
- # req = Net::HTTP::Post.new(uri) # => #<Net::HTTP::Post POST>
- # req.body_stream # => nil
- # require 'stringio'
- # req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8>
- # req.body_stream # => #<StringIO:0x0000027d1e5affa8>
- #
def body_stream=(input)
@body = nil
@body_stream = input
@@ -212,15 +136,15 @@ class Net::HTTPGenericRequest
return unless @uri
if ssl
- scheme = 'https'
+ scheme = 'https'.freeze
klass = URI::HTTPS
else
- scheme = 'http'
+ scheme = 'http'.freeze
klass = URI::HTTP
end
if host = self['host']
- host.sub!(/:.*/m, '')
+ host.sub!(/:.*/m, ''.freeze)
elsif host = @uri.host
else
host = addr
@@ -316,7 +240,7 @@ class Net::HTTPGenericRequest
boundary ||= SecureRandom.urlsafe_base64(40)
chunked_p = chunked?
- buf = +''
+ buf = ''
params.each do |key, value, h={}|
key = quote_string(key, charset)
filename =
@@ -401,7 +325,7 @@ class Net::HTTPGenericRequest
if /[\r\n]/ =~ reqline
raise ArgumentError, "A Request-Line must not contain CR or LF"
end
- buf = +''
+ buf = ""
buf << reqline << "\r\n"
each_capitalized do |k,v|
buf << "#{k}: #{v}\r\n"
diff --git a/lib/net/http/header.rb b/lib/net/http/header.rb
index 6660c8075a..40c119a353 100644
--- a/lib/net/http/header.rb
+++ b/lib/net/http/header.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# The \HTTPHeader module provides access to \HTTP headers.
#
@@ -179,8 +179,6 @@
# - #each_value: Passes each string field value to the block.
#
module Net::HTTPHeader
- MAX_KEY_LENGTH = 1024
- MAX_FIELD_LENGTH = 65536
def initialize_http_header(initheader) #:nodoc:
@header = {}
@@ -191,12 +189,6 @@ module Net::HTTPHeader
warn "net/http: nil HTTP header: #{key}", uplevel: 3 if $VERBOSE
else
value = value.strip # raise error for invalid byte sequences
- if key.to_s.bytesize > MAX_KEY_LENGTH
- raise ArgumentError, "too long (#{key.bytesize} bytes) header: #{key[0, 30].inspect}..."
- end
- if value.to_s.bytesize > MAX_FIELD_LENGTH
- raise ArgumentError, "header #{key} has too long field value: #{value.bytesize}"
- end
if value.count("\r\n") > 0
raise ArgumentError, "header #{key} has field value #{value.inspect}, this cannot include CR/LF"
end
@@ -699,14 +691,10 @@ module Net::HTTPHeader
# res.content_type # => "application/json"
#
def content_type
- main = main_type()
- return nil unless main
-
- sub = sub_type()
- if sub
- "#{main}/#{sub}"
- else
- main
+ return nil unless main_type()
+ if sub_type()
+ then "#{main_type()}/#{sub_type()}"
+ else main_type()
end
end
@@ -775,38 +763,19 @@ module Net::HTTPHeader
alias content_type= set_content_type
- # Sets the request body to a URL-encoded string derived from argument +params+,
- # and sets request header field <tt>'Content-Type'</tt>
- # to <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The resulting request is suitable for HTTP request +POST+ or +PUT+.
- #
- # Argument +params+ must be suitable for use as argument +enum+ to
- # {URI.encode_www_form}[rdoc-ref:URI.encode_www_form].
- #
- # With only argument +params+ given,
- # sets the body to a URL-encoded string with the default separator <tt>'&'</tt>:
+ # Set header fields and a body from HTML form data.
+ # +params+ should be an Array of Arrays or
+ # a Hash containing HTML form data.
+ # Optional argument +sep+ means data record separator.
#
- # req = Net::HTTP::Post.new('example.com')
+ # Values are URL encoded as necessary and the content-type is set to
+ # application/x-www-form-urlencoded
#
- # req.set_form_data(q: 'ruby', lang: 'en')
- # req.body # => "q=ruby&lang=en"
- # req['Content-Type'] # => "application/x-www-form-urlencoded"
+ # Example:
#
- # req.set_form_data([['q', 'ruby'], ['lang', 'en']])
- # req.body # => "q=ruby&lang=en"
- #
- # req.set_form_data(q: ['ruby', 'perl'], lang: 'en')
- # req.body # => "q=ruby&q=perl&lang=en"
- #
- # req.set_form_data([['q', 'ruby'], ['q', 'perl'], ['lang', 'en']])
- # req.body # => "q=ruby&q=perl&lang=en"
- #
- # With string argument +sep+ also given,
- # uses that string as the separator:
- #
- # req.set_form_data({q: 'ruby', lang: 'en'}, '|')
- # req.body # => "q=ruby|lang=en"
+ # http.form_data = {"q" => "ruby", "lang" => "en"}
+ # http.form_data = {"q" => ["ruby", "perl"], "lang" => "en"}
+ # http.set_form_data({"q" => "ruby", "lang" => "en"}, ';')
#
# Net::HTTPHeader#form_data= is an alias for Net::HTTPHeader#set_form_data.
def set_form_data(params, sep = '&')
@@ -818,108 +787,56 @@ module Net::HTTPHeader
alias form_data= set_form_data
- # Stores form data to be used in a +POST+ or +PUT+ request.
- #
- # The form data given in +params+ consists of zero or more fields;
- # each field is:
- #
- # - A scalar value.
- # - A name/value pair.
- # - An IO stream opened for reading.
- #
- # Argument +params+ should be an
- # {Enumerable}[rdoc-ref:Enumerable@Enumerable+in+Ruby+Classes]
- # (method <tt>params.map</tt> will be called),
- # and is often an array or hash.
- #
- # First, we set up a request:
- #
- # _uri = uri.dup
- # _uri.path ='/posts'
- # req = Net::HTTP::Post.new(_uri)
- #
- # <b>Argument +params+ As an Array</b>
- #
- # When +params+ is an array,
- # each of its elements is a subarray that defines a field;
- # the subarray may contain:
- #
- # - One string:
- #
- # req.set_form([['foo'], ['bar'], ['baz']])
- #
- # - Two strings:
- #
- # req.set_form([%w[foo 0], %w[bar 1], %w[baz 2]])
- #
- # - When argument +enctype+ (see below) is given as
- # <tt>'multipart/form-data'</tt>:
- #
- # - A string name and an IO stream opened for reading:
- #
- # require 'stringio'
- # req.set_form([['file', StringIO.new('Ruby is cool.')]])
- #
- # - A string name, an IO stream opened for reading,
- # and an options hash, which may contain these entries:
- #
- # - +:filename+: The name of the file to use.
- # - +:content_type+: The content type of the uploaded file.
- #
- # Example:
- #
- # req.set_form([['file', file, {filename: "other-filename.foo"}]]
- #
- # The various forms may be mixed:
- #
- # req.set_form(['foo', %w[bar 1], ['file', file]])
- #
- # <b>Argument +params+ As a Hash</b>
- #
- # When +params+ is a hash,
- # each of its entries is a name/value pair that defines a field:
- #
- # - The name is a string.
- # - The value may be:
- #
- # - +nil+.
- # - Another string.
- # - An IO stream opened for reading
- # (only when argument +enctype+ -- see below -- is given as
- # <tt>'multipart/form-data'</tt>).
- #
- # Examples:
- #
- # # Nil-valued fields.
- # req.set_form({'foo' => nil, 'bar' => nil, 'baz' => nil})
- #
- # # String-valued fields.
- # req.set_form({'foo' => 0, 'bar' => 1, 'baz' => 2})
- #
- # # IO-valued field.
- # require 'stringio'
- # req.set_form({'file' => StringIO.new('Ruby is cool.')})
- #
- # # Mixture of fields.
- # req.set_form({'foo' => nil, 'bar' => 1, 'file' => file})
- #
- # Optional argument +enctype+ specifies the value to be given
- # to field <tt>'Content-Type'</tt>, and must be one of:
- #
- # - <tt>'application/x-www-form-urlencoded'</tt> (the default).
- # - <tt>'multipart/form-data'</tt>;
- # see {RFC 7578}[https://www.rfc-editor.org/rfc/rfc7578].
- #
- # Optional argument +formopt+ is a hash of options
- # (applicable only when argument +enctype+
- # is <tt>'multipart/form-data'</tt>)
- # that may include the following entries:
- #
- # - +:boundary+: The value is the boundary string for the multipart message.
- # If not given, the boundary is a random string.
- # See {Boundary}[https://www.rfc-editor.org/rfc/rfc7578#section-4.1].
- # - +:charset+: Value is the character set for the form submission.
- # Field names and values of non-file fields should be encoded with this charset.
+ # Set an HTML form data set.
+ # +params+ :: The form data to set, which should be an enumerable.
+ # See below for more details.
+ # +enctype+ :: The content type to use to encode the form submission,
+ # which should be application/x-www-form-urlencoded or
+ # multipart/form-data.
+ # +formopt+ :: An options hash, supporting the following options:
+ # :boundary :: The boundary of the multipart message. If
+ # not given, a random boundary will be used.
+ # :charset :: The charset of the form submission. All
+ # field names and values of non-file fields
+ # should be encoded with this charset.
+ #
+ # Each item of params should respond to +each+ and yield 2-3 arguments,
+ # or an array of 2-3 elements. The arguments yielded should be:
+ #
+ # - The name of the field.
+ # - The value of the field, it should be a String or a File or IO-like.
+ # - An options hash, supporting the following options
+ # (used only for file uploads); entries:
+ #
+ # - +:filename+: The name of the file to use.
+ # - +:content_type+: The content type of the uploaded file.
+ #
+ # Each item is a file field or a normal field.
+ # If +value+ is a File object or the +opt+ hash has a :filename key,
+ # the item is treated as a file field.
+ #
+ # If Transfer-Encoding is set as chunked, this sends the request using
+ # chunked encoding. Because chunked encoding is HTTP/1.1 feature,
+ # you should confirm that the server supports HTTP/1.1 before using
+ # chunked encoding.
+ #
+ # Example:
+ #
+ # req.set_form([["q", "ruby"], ["lang", "en"]])
+ #
+ # req.set_form({"f"=>File.open('/path/to/filename')},
+ # "multipart/form-data",
+ # charset: "UTF-8",
+ # )
+ #
+ # req.set_form([["f",
+ # File.open('/path/to/filename.bar'),
+ # {filename: "other-filename.foo"}
+ # ]],
+ # "multipart/form-data",
+ # )
+ #
+ # See also RFC 2388, RFC 2616, HTML 4.01, and HTML5
#
def set_form(params, enctype='application/x-www-form-urlencoded', formopt={})
@body_data = params
@@ -935,24 +852,12 @@ module Net::HTTPHeader
end
end
- # Sets header <tt>'Authorization'</tt> using the given
- # +account+ and +password+ strings:
- #
- # req.basic_auth('my_account', 'my_password')
- # req['Authorization']
- # # => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
- #
+ # Set the Authorization: header for "Basic" authorization.
def basic_auth(account, password)
@header['authorization'] = [basic_encode(account, password)]
end
- # Sets header <tt>'Proxy-Authorization'</tt> using the given
- # +account+ and +password+ strings:
- #
- # req.proxy_basic_auth('my_account', 'my_password')
- # req['Proxy-Authorization']
- # # => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
- #
+ # Set Proxy-Authorization: header for "Basic" authorization.
def proxy_basic_auth(account, password)
@header['proxy-authorization'] = [basic_encode(account, password)]
end
@@ -962,7 +867,6 @@ module Net::HTTPHeader
end
private :basic_encode
-# Returns whether the HTTP session is to be closed.
def connection_close?
token = /(?:\A|,)\s*close\s*(?:\z|,)/i
@header['connection']&.grep(token) {return true}
@@ -970,7 +874,6 @@ module Net::HTTPHeader
false
end
-# Returns whether the HTTP session is to be kept alive.
def connection_keep_alive?
token = /(?:\A|,)\s*keep-alive\s*(?:\z|,)/i
@header['connection']&.grep(token) {return true}
diff --git a/lib/net/http/net-http.gemspec b/lib/net/http/net-http.gemspec
index 0021136793..a7f122fc0e 100644
--- a/lib/net/http/net-http.gemspec
+++ b/lib/net/http/net-http.gemspec
@@ -2,14 +2,9 @@
name = File.basename(__FILE__, ".gemspec")
version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
- file = File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")
- begin
- break File.foreach(file, mode: "rb") do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end
- rescue SystemCallError
- next
- end
+ 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|
@@ -30,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{\A(?:(?:test|spec|features)/|\.git)}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.require_paths = ["lib"]
diff --git a/lib/net/http/proxy_delta.rb b/lib/net/http/proxy_delta.rb
index e7d30def64..a2f770ebdb 100644
--- a/lib/net/http/proxy_delta.rb
+++ b/lib/net/http/proxy_delta.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
module Net::HTTP::ProxyDelta #:nodoc: internal use only
private
diff --git a/lib/net/http/request.rb b/lib/net/http/request.rb
index 4a138572e9..f3d32edb62 100644
--- a/lib/net/http/request.rb
+++ b/lib/net/http/request.rb
@@ -1,55 +1,10 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
-# This class is the base class for \Net::HTTP request classes.
-# The class should not be used directly;
-# instead you should use its subclasses, listed below.
-#
-# == Creating a Request
-#
-# An request object may be created with either a URI or a string hostname:
-#
-# require 'net/http'
-# uri = URI('https://jsonplaceholder.typicode.com/')
-# req = Net::HTTP::Get.new(uri) # => #<Net::HTTP::Get GET>
-# req = Net::HTTP::Get.new(uri.hostname) # => #<Net::HTTP::Get GET>
-#
-# And with any of the subclasses:
-#
-# req = Net::HTTP::Head.new(uri) # => #<Net::HTTP::Head HEAD>
-# req = Net::HTTP::Post.new(uri) # => #<Net::HTTP::Post POST>
-# req = Net::HTTP::Put.new(uri) # => #<Net::HTTP::Put PUT>
-# # ...
-#
-# The new instance is suitable for use as the argument to Net::HTTP#request.
-#
-# == Request Headers
+# This class is the base class for \Net::HTTP request classes;
+# it wraps together the request path and the request headers.
#
-# A new request object has these header fields by default:
-#
-# req.to_hash
-# # =>
-# {"accept-encoding"=>["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
-# "accept"=>["*/*"],
-# "user-agent"=>["Ruby"],
-# "host"=>["jsonplaceholder.typicode.com"]}
-#
-# See:
-#
-# - {Request header Accept-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Accept-Encoding]
-# and {Compression and Decompression}[rdoc-ref:Net::HTTP@Compression+and+Decompression].
-# - {Request header Accept}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#accept-request-header].
-# - {Request header User-Agent}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#user-agent-request-header].
-# - {Request header Host}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#host-request-header].
-#
-# You can add headers or override default headers:
-#
-# # res = Net::HTTP::Get.new(uri, {'foo' => '0', 'bar' => '1'})
-#
-# This class (and therefore its subclasses) also includes (indirectly)
-# module Net::HTTPHeader, which gives access to its
-# {methods for setting headers}[rdoc-ref:Net::HTTPHeader@Setters].
-#
-# == Request Subclasses
+# The class should not be used directly;
+# instead you should use its subclasses.
#
# Subclasses for HTTP requests:
#
diff --git a/lib/net/http/requests.rb b/lib/net/http/requests.rb
index 5724164205..294b8e8841 100644
--- a/lib/net/http/requests.rb
+++ b/lib/net/http/requests.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
# HTTP/1.1 methods --- RFC2616
@@ -13,8 +13,6 @@
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Properties:
#
# - Request body: optional.
@@ -45,8 +43,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Properties:
#
# - Request body: optional.
@@ -79,8 +75,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Properties:
#
# - Request body: yes.
@@ -114,8 +108,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Properties:
#
# - Request body: yes.
@@ -142,8 +134,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Properties:
#
# - Request body: optional.
@@ -173,8 +163,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Properties:
#
# - Request body: optional.
@@ -204,8 +192,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Properties:
#
# - Request body: no.
@@ -238,8 +224,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Properties:
#
# - Request body: yes.
@@ -273,8 +257,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Related:
#
# - Net::HTTP#propfind: sends +PROPFIND+ request, returns response object.
@@ -296,8 +278,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Related:
#
# - Net::HTTP#proppatch: sends +PROPPATCH+ request, returns response object.
@@ -319,8 +299,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Related:
#
# - Net::HTTP#mkcol: sends +MKCOL+ request, returns response object.
@@ -342,8 +320,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Related:
#
# - Net::HTTP#copy: sends +COPY+ request, returns response object.
@@ -365,8 +341,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Related:
#
# - Net::HTTP#move: sends +MOVE+ request, returns response object.
@@ -388,8 +362,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Related:
#
# - Net::HTTP#lock: sends +LOCK+ request, returns response object.
@@ -411,8 +383,6 @@ end
# http.request(req)
# end
#
-# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
-#
# Related:
#
# - Net::HTTP#unlock: sends +UNLOCK+ request, returns response object.
diff --git a/lib/net/http/response.rb b/lib/net/http/response.rb
index 40de963868..83853ffd19 100644
--- a/lib/net/http/response.rb
+++ b/lib/net/http/response.rb
@@ -1,6 +1,6 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
-# This class is the base class for \Net::HTTP response classes.
+# This class is the base class for \Net::HTTP request classes.
#
# == About the Examples
#
@@ -224,32 +224,13 @@ class Net::HTTPResponse
# Accept-Encoding header from the user.
attr_accessor :decode_content
- # Returns the value set by body_encoding=, or +false+ if none;
- # see #body_encoding=.
+ # The encoding to use for the response body. If Encoding, use that encoding.
+ # If other true value, attempt to detect the appropriate encoding, and use
+ # that.
attr_reader :body_encoding
- # Sets the encoding that should be used when reading the body:
- #
- # - If the given value is an Encoding object, that encoding will be used.
- # - Otherwise if the value is a string, the value of
- # {Encoding#find(value)}[rdoc-ref:Encoding.find]
- # will be used.
- # - Otherwise an encoding will be deduced from the body itself.
- #
- # Examples:
- #
- # http = Net::HTTP.new(hostname)
- # req = Net::HTTP::Get.new('/')
- #
- # http.request(req) do |res|
- # p res.body.encoding # => #<Encoding:ASCII-8BIT>
- # end
- #
- # http.request(req) do |res|
- # res.body_encoding = "UTF-8"
- # p res.body.encoding # => #<Encoding:UTF-8>
- # end
- #
+ # Set the encoding to use for the response body. If given a String, find
+ # the related Encoding.
def body_encoding=(value)
value = Encoding.find(value) if value.is_a?(String)
@body_encoding = value
@@ -273,7 +254,7 @@ class Net::HTTPResponse
def error! #:nodoc:
message = @code
- message = "#{message} #{@message.dump}" if @message
+ message += ' ' + @message.dump if @message
raise error_type().new(message, self)
end
@@ -366,7 +347,6 @@ class Net::HTTPResponse
@body = nil
end
@read = true
- return if @body.nil?
case enc = @body_encoding
when Encoding, false, nil
@@ -382,26 +362,26 @@ class Net::HTTPResponse
@body
end
- # Returns the string response body;
- # note that repeated calls for the unmodified body return a cached string:
+ # Returns the full entity body.
#
- # path = '/todos/1'
- # Net::HTTP.start(hostname) do |http|
- # res = http.get(path)
- # p res.body
- # p http.head(path).body # No body.
- # end
+ # Calling this method a second or subsequent time will return the
+ # string already read.
#
- # Output:
+ # http.request_get('/index.html') {|res|
+ # puts res.body
+ # }
#
- # "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n}"
- # nil
+ # http.request_get('/index.html') {|res|
+ # p res.body.object_id # 538149362
+ # p res.body.object_id # 538149362
+ # }
#
def body
read_body()
end
- # Sets the body of the response to the given value.
+ # Because it may be necessary to modify the body, Eg, decompression
+ # this method facilitates that.
def body=(value)
@body = value
end
@@ -640,7 +620,7 @@ class Net::HTTPResponse
end
def stream_check
- raise IOError, 'attempt to read body out of block' if @socket.nil? || @socket.closed?
+ raise IOError, 'attempt to read body out of block' if @socket.closed?
end
def procdest(dest, block)
@@ -649,7 +629,7 @@ class Net::HTTPResponse
if block
Net::ReadAdapter.new(block)
else
- dest || +''
+ dest || ''
end
end
diff --git a/lib/net/http/responses.rb b/lib/net/http/responses.rb
index 6f6fb8d055..b2dad10537 100644
--- a/lib/net/http/responses.rb
+++ b/lib/net/http/responses.rb
@@ -85,8 +85,6 @@ module Net
#
# A +Continue+ response indicates that the server has received the request headers.
#
- # :include: doc/net-http/included_getters.rdoc
- #
# References:
#
# - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/100].
@@ -102,8 +100,6 @@ module Net
# The <tt>Switching Protocol<tt> response indicates that the server has received
# a request to switch protocols, and has agreed to do so.
#
- # :include: doc/net-http/included_getters.rdoc
- #
# References:
#
# - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/101].
@@ -119,11 +115,8 @@ module Net
# The +Processing+ response indicates that the server has received
# and is processing the request, but no response is available yet.
#
- # :include: doc/net-http/included_getters.rdoc
- #
# References:
#
- # - {RFC 2518}[https://www.rfc-editor.org/rfc/rfc2518#section-10.1].
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#102].
#
class HTTPProcessing < HTTPInformation
@@ -136,12 +129,9 @@ module Net
# and is processing the request, and contains certain headers;
# the final response is not available yet.
#
- # :include: doc/net-http/included_getters.rdoc
- #
# References:
#
# - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103].
- # - {RFC 8297}[https://www.rfc-editor.org/rfc/rfc8297.html#section-2].
# - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#103].
#
class HTTPEarlyHints < HTTPInformation
@@ -152,15 +142,7 @@ module Net
#
# The +OK+ response indicates that the server has received
# a request and has responded successfully.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-200-ok].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#200].
- #
+ # See {200 OK}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#200].
class HTTPOK < HTTPSuccess
HAS_BODY = true
end
@@ -169,15 +151,7 @@ module Net
#
# The +Created+ response indicates that the server has received
# and has fulfilled a request to create a new resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-201-created].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#201].
- #
+ # See {201 Created}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#201].
class HTTPCreated < HTTPSuccess
HAS_BODY = true
end
@@ -186,15 +160,7 @@ module Net
#
# The +Accepted+ response indicates that the server has received
# and is processing a request, but the processing has not yet been completed.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-202-accepted].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#202].
- #
+ # See {202 Accepted}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#202].
class HTTPAccepted < HTTPSuccess
HAS_BODY = true
end
@@ -205,15 +171,7 @@ module Net
# is a transforming proxy (such as a Web accelerator)
# that received a 200 OK response from its origin,
# and is returning a modified version of the origin's response.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/203].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-203-non-authoritative-infor].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#203].
- #
+ # See {203 Non-Authoritative Information}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#203].
class HTTPNonAuthoritativeInformation < HTTPSuccess
HAS_BODY = true
end
@@ -222,15 +180,7 @@ module Net
#
# The <tt>No Content</tt> response indicates that the server
# successfully processed the request, and is not returning any content.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-204-no-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#204].
- #
+ # See {204 No Content}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#204].
class HTTPNoContent < HTTPSuccess
HAS_BODY = false
end
@@ -240,15 +190,7 @@ module Net
# The <tt>Reset Content</tt> response indicates that the server
# successfully processed the request,
# asks that the client reset its document view, and is not returning any content.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/205].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-205-reset-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#205].
- #
+ # See {205 Reset Content}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#205].
class HTTPResetContent < HTTPSuccess
HAS_BODY = false
end
@@ -258,15 +200,7 @@ module Net
# The <tt>Partial Content</tt> response indicates that the server is delivering
# only part of the resource (byte serving)
# due to a Range header in the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-206-partial-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#206].
- #
+ # See {206 Partial Content}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#206].
class HTTPPartialContent < HTTPSuccess
HAS_BODY = true
end
@@ -276,14 +210,7 @@ module Net
# The <tt>Multi-Status (WebDAV)</tt> response indicates that the server
# has received the request,
# and that the message body can contain a number of separate response codes.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 4818}[https://www.rfc-editor.org/rfc/rfc4918#section-11.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#207].
- #
+ # See {207 Multi-Status (WebDAV)}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#207].
class HTTPMultiStatus < HTTPSuccess
HAS_BODY = true
end
@@ -295,14 +222,7 @@ module Net
# and that the members of a DAV binding have already been enumerated
# in a preceding part of the (multi-status) response,
# and are not being included again.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 5842}[https://www.rfc-editor.org/rfc/rfc5842.html#section-7.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#208].
- #
+ # See {208 Already Reported (WebDAV)}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#208].
class HTTPAlreadyReported < HTTPSuccess
HAS_BODY = true
end
@@ -312,14 +232,7 @@ module Net
# The <tt>IM Used</tt> response indicates that the server has fulfilled a request
# for the resource, and the response is a representation of the result
# of one or more instance-manipulations applied to the current instance.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 3229}[https://www.rfc-editor.org/rfc/rfc3229.html#section-10.4.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#226].
- #
+ # See {226 IM Used}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#226].
class HTTPIMUsed < HTTPSuccess
HAS_BODY = true
end
@@ -328,15 +241,7 @@ module Net
#
# The <tt>Multiple Choices</tt> response indicates that the server
# offers multiple options for the resource from which the client may choose.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/300].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-300-multiple-choices].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#300].
- #
+ # See {300 Multiple Choices}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#300].
class HTTPMultipleChoices < HTTPRedirection
HAS_BODY = true
end
@@ -346,15 +251,7 @@ module Net
#
# The <tt>Moved Permanently</tt> response indicates that links or records
# returning this response should be updated to use the given URL.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/301].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-301-moved-permanently].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#301].
- #
+ # See {301 Moved Permanently}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#301].
class HTTPMovedPermanently < HTTPRedirection
HAS_BODY = true
end
@@ -363,15 +260,7 @@ module Net
#
# The <tt>Found</tt> response indicates that the client
# should look at (browse to) another URL.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-302-found].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#302].
- #
+ # See {302 Found}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#302].
class HTTPFound < HTTPRedirection
HAS_BODY = true
end
@@ -380,15 +269,7 @@ module Net
# Response class for <tt>See Other</tt> responses (status code 303).
#
# The response to the request can be found under another URI using the GET method.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/303].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-303-see-other].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#303].
- #
+ # See {303 See Other}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#303].
class HTTPSeeOther < HTTPRedirection
HAS_BODY = true
end
@@ -397,15 +278,7 @@ module Net
#
# Indicates that the resource has not been modified since the version
# specified by the request headers.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-304-not-modified].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#304].
- #
+ # See {304 Not Modified}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#304].
class HTTPNotModified < HTTPRedirection
HAS_BODY = false
end
@@ -414,14 +287,7 @@ module Net
#
# The requested resource is available only through a proxy,
# whose address is provided in the response.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-305-use-proxy].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#305].
- #
+ # See {305 Use Proxy}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#305].
class HTTPUseProxy < HTTPRedirection
HAS_BODY = false
end
@@ -430,15 +296,7 @@ module Net
#
# The request should be repeated with another URI;
# however, future requests should still use the original URI.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-307-temporary-redirect].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#307].
- #
+ # See {307 Temporary Redirect}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#307].
class HTTPTemporaryRedirect < HTTPRedirection
HAS_BODY = true
end
@@ -446,15 +304,7 @@ module Net
# Response class for <tt>Permanent Redirect</tt> responses (status code 308).
#
# This and all future requests should be directed to the given URI.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-308-permanent-redirect].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#308].
- #
+ # See {308 Permanent Redirect}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#308].
class HTTPPermanentRedirect < HTTPRedirection
HAS_BODY = true
end
@@ -462,15 +312,7 @@ module Net
# Response class for <tt>Bad Request</tt> responses (status code 400).
#
# The server cannot or will not process the request due to an apparent client error.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-400-bad-request].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#400].
- #
+ # See {400 Bad Request}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#400].
class HTTPBadRequest < HTTPClientError
HAS_BODY = true
end
@@ -478,15 +320,7 @@ module Net
# Response class for <tt>Unauthorized</tt> responses (status code 401).
#
# Authentication is required, but either was not provided or failed.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-401-unauthorized].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#401].
- #
+ # See {401 Unauthorized}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#401].
class HTTPUnauthorized < HTTPClientError
HAS_BODY = true
end
@@ -494,15 +328,7 @@ module Net
# Response class for <tt>Payment Required</tt> responses (status code 402).
#
# Reserved for future use.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/402].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-402-payment-required].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#402].
- #
+ # See {402 Payment Required}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#402].
class HTTPPaymentRequired < HTTPClientError
HAS_BODY = true
end
@@ -511,15 +337,7 @@ module Net
#
# The request contained valid data and was understood by the server,
# but the server is refusing action.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-403-forbidden].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#403].
- #
+ # See {403 Forbidden}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#403].
class HTTPForbidden < HTTPClientError
HAS_BODY = true
end
@@ -527,15 +345,7 @@ module Net
# Response class for <tt>Not Found</tt> responses (status code 404).
#
# The requested resource could not be found but may be available in the future.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-404-not-found].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#404].
- #
+ # See {404 Not Found}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#404].
class HTTPNotFound < HTTPClientError
HAS_BODY = true
end
@@ -543,15 +353,7 @@ module Net
# Response class for <tt>Method Not Allowed</tt> responses (status code 405).
#
# The request method is not supported for the requested resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-405-method-not-allowed].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#405].
- #
+ # See {405 Method Not Allowed}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#405].
class HTTPMethodNotAllowed < HTTPClientError
HAS_BODY = true
end
@@ -560,15 +362,7 @@ module Net
#
# The requested resource is capable of generating only content
# that not acceptable according to the Accept headers sent in the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/406].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-406-not-acceptable].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#406].
- #
+ # See {406 Not Acceptable}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#406].
class HTTPNotAcceptable < HTTPClientError
HAS_BODY = true
end
@@ -576,15 +370,7 @@ module Net
# Response class for <tt>Proxy Authentication Required</tt> responses (status code 407).
#
# The client must first authenticate itself with the proxy.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/407].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-407-proxy-authentication-re].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#407].
- #
+ # See {407 Proxy Authentication Required}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#407].
class HTTPProxyAuthenticationRequired < HTTPClientError
HAS_BODY = true
end
@@ -592,15 +378,7 @@ module Net
# Response class for <tt>Request Timeout</tt> responses (status code 408).
#
# The server timed out waiting for the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-408-request-timeout].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#408].
- #
+ # See {408 Request Timeout}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#408].
class HTTPRequestTimeout < HTTPClientError
HAS_BODY = true
end
@@ -609,15 +387,7 @@ module Net
# Response class for <tt>Conflict</tt> responses (status code 409).
#
# The request could not be processed because of conflict in the current state of the resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-409-conflict].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#409].
- #
+ # See {409 Conflict}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#409].
class HTTPConflict < HTTPClientError
HAS_BODY = true
end
@@ -626,15 +396,7 @@ module Net
#
# The resource requested was previously in use but is no longer available
# and will not be available again.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/410].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-410-gone].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#410].
- #
+ # See {410 Gone}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#410].
class HTTPGone < HTTPClientError
HAS_BODY = true
end
@@ -643,15 +405,7 @@ module Net
#
# The request did not specify the length of its content,
# which is required by the requested resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/411].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-411-length-required].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#411].
- #
+ # See {411 Length Required}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#411].
class HTTPLengthRequired < HTTPClientError
HAS_BODY = true
end
@@ -660,15 +414,7 @@ module Net
#
# The server does not meet one of the preconditions
# specified in the request headers.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/412].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-412-precondition-failed].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#412].
- #
+ # See {412 Precondition Failed}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#412].
class HTTPPreconditionFailed < HTTPClientError
HAS_BODY = true
end
@@ -676,15 +422,7 @@ module Net
# Response class for <tt>Payload Too Large</tt> responses (status code 413).
#
# The request is larger than the server is willing or able to process.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/413].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-413-content-too-large].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#413].
- #
+ # See {413 Payload Too Large}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#413].
class HTTPPayloadTooLarge < HTTPClientError
HAS_BODY = true
end
@@ -693,15 +431,7 @@ module Net
# Response class for <tt>URI Too Long</tt> responses (status code 414).
#
# The URI provided was too long for the server to process.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/414].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-414-uri-too-long].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#414].
- #
+ # See {414 URI Too Long}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#414].
class HTTPURITooLong < HTTPClientError
HAS_BODY = true
end
@@ -711,15 +441,7 @@ module Net
# Response class for <tt>Unsupported Media Type</tt> responses (status code 415).
#
# The request entity has a media type which the server or resource does not support.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/415].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-415-unsupported-media-type].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#415].
- #
+ # See {415 Unsupported Media Type}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#415].
class HTTPUnsupportedMediaType < HTTPClientError
HAS_BODY = true
end
@@ -727,15 +449,7 @@ module Net
# Response class for <tt>Range Not Satisfiable</tt> responses (status code 416).
#
# The request entity has a media type which the server or resource does not support.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-416-range-not-satisfiable].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#416].
- #
+ # See {416 Range Not Satisfiable}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#416].
class HTTPRangeNotSatisfiable < HTTPClientError
HAS_BODY = true
end
@@ -744,15 +458,7 @@ module Net
# Response class for <tt>Expectation Failed</tt> responses (status code 417).
#
# The server cannot meet the requirements of the Expect request-header field.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/417].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-417-expectation-failed].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#417].
- #
+ # See {417 Expectation Failed}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#417].
class HTTPExpectationFailed < HTTPClientError
HAS_BODY = true
end
@@ -765,14 +471,7 @@ module Net
# Response class for <tt>Misdirected Request</tt> responses (status code 421).
#
# The request was directed at a server that is not able to produce a response.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-421-misdirected-request].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#421].
- #
+ # See {421 Misdirected Request}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#421].
class HTTPMisdirectedRequest < HTTPClientError
HAS_BODY = true
end
@@ -780,15 +479,7 @@ module Net
# Response class for <tt>Unprocessable Entity</tt> responses (status code 422).
#
# The request was well-formed but had semantic errors.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-422-unprocessable-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422].
- #
+ # See {422 Unprocessable Entity}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422].
class HTTPUnprocessableEntity < HTTPClientError
HAS_BODY = true
end
@@ -796,14 +487,7 @@ module Net
# Response class for <tt>Locked (WebDAV)</tt> responses (status code 423).
#
# The requested resource is locked.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 4918}[https://www.rfc-editor.org/rfc/rfc4918#section-11.3].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#423].
- #
+ # See {423 Locked (WebDAV)}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#423].
class HTTPLocked < HTTPClientError
HAS_BODY = true
end
@@ -812,14 +496,6 @@ module Net
#
# The request failed because it depended on another request and that request failed.
# See {424 Failed Dependency (WebDAV)}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 4918}[https://www.rfc-editor.org/rfc/rfc4918#section-11.4].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
- #
class HTTPFailedDependency < HTTPClientError
HAS_BODY = true
end
@@ -830,15 +506,7 @@ module Net
# Response class for <tt>Upgrade Required</tt> responses (status code 426).
#
# The client should switch to the protocol given in the Upgrade header field.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/426].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-426-upgrade-required].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#426].
- #
+ # See {426 Upgrade Required}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#426].
class HTTPUpgradeRequired < HTTPClientError
HAS_BODY = true
end
@@ -846,15 +514,7 @@ module Net
# Response class for <tt>Precondition Required</tt> responses (status code 428).
#
# The origin server requires the request to be conditional.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/428].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-3].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#428].
- #
+ # See {428 Precondition Required}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#428].
class HTTPPreconditionRequired < HTTPClientError
HAS_BODY = true
end
@@ -862,15 +522,7 @@ module Net
# Response class for <tt>Too Many Requests</tt> responses (status code 429).
#
# The user has sent too many requests in a given amount of time.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-4].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#429].
- #
+ # See {429 Too Many Requests}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#429].
class HTTPTooManyRequests < HTTPClientError
HAS_BODY = true
end
@@ -879,15 +531,7 @@ module Net
#
# An individual header field is too large,
# or all the header fields collectively, are too large.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/431].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-5].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#431].
- #
+ # See {431 Request Header Fields Too Large}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#431].
class HTTPRequestHeaderFieldsTooLarge < HTTPClientError
HAS_BODY = true
end
@@ -896,15 +540,7 @@ module Net
#
# A server operator has received a legal demand to deny access to a resource or to a set of resources
# that includes the requested resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/451].
- # - {RFC 7725}[https://www.rfc-editor.org/rfc/rfc7725.html#section-3].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#451].
- #
+ # See {451 Unavailable For Legal Reasons}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#451].
class HTTPUnavailableForLegalReasons < HTTPClientError
HAS_BODY = true
end
@@ -916,15 +552,7 @@ module Net
# Response class for <tt>Internal Server Error</tt> responses (status code 500).
#
# An unexpected condition was encountered and no more specific message is suitable.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-500-internal-server-error].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#500].
- #
+ # See {500 Internal Server Error}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#500].
class HTTPInternalServerError < HTTPServerError
HAS_BODY = true
end
@@ -933,15 +561,7 @@ module Net
#
# The server either does not recognize the request method,
# or it lacks the ability to fulfil the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-501-not-implemented].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#501].
- #
+ # See {501 Not Implemented}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#501].
class HTTPNotImplemented < HTTPServerError
HAS_BODY = true
end
@@ -950,15 +570,7 @@ module Net
#
# The server was acting as a gateway or proxy
# and received an invalid response from the upstream server.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-502-bad-gateway].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#502].
- #
+ # See {502 Bad Gateway}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#502].
class HTTPBadGateway < HTTPServerError
HAS_BODY = true
end
@@ -967,15 +579,7 @@ module Net
#
# The server cannot handle the request
# (because it is overloaded or down for maintenance).
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-503-service-unavailable].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#503].
- #
+ # See {503 Service Unavailable}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#503].
class HTTPServiceUnavailable < HTTPServerError
HAS_BODY = true
end
@@ -984,15 +588,7 @@ module Net
#
# The server was acting as a gateway or proxy
# and did not receive a timely response from the upstream server.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-504-gateway-timeout].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#504].
- #
+ # See {504 Gateway Timeout}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#504].
class HTTPGatewayTimeout < HTTPServerError
HAS_BODY = true
end
@@ -1001,15 +597,7 @@ module Net
# Response class for <tt>HTTP Version Not Supported</tt> responses (status code 505).
#
# The server does not support the HTTP version used in the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/505].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-505-http-version-not-suppor].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#505].
- #
+ # See {505 HTTP Version Not Supported}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#505].
class HTTPVersionNotSupported < HTTPServerError
HAS_BODY = true
end
@@ -1017,15 +605,7 @@ module Net
# Response class for <tt>Variant Also Negotiates</tt> responses (status code 506).
#
# Transparent content negotiation for the request results in a circular reference.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/506].
- # - {RFC 2295}[https://www.rfc-editor.org/rfc/rfc2295#section-8.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#506].
- #
+ # See {506 Variant Also Negotiates}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#506].
class HTTPVariantAlsoNegotiates < HTTPServerError
HAS_BODY = true
end
@@ -1033,15 +613,7 @@ module Net
# Response class for <tt>Insufficient Storage (WebDAV)</tt> responses (status code 507).
#
# The server is unable to store the representation needed to complete the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/507].
- # - {RFC 4918}[https://www.rfc-editor.org/rfc/rfc4918#section-11.5].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#507].
- #
+ # See {507 Insufficient Storage (WebDAV)}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#507].
class HTTPInsufficientStorage < HTTPServerError
HAS_BODY = true
end
@@ -1049,15 +621,7 @@ module Net
# Response class for <tt>Loop Detected (WebDAV)</tt> responses (status code 508).
#
# The server detected an infinite loop while processing the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/508].
- # - {RFC 5942}[https://www.rfc-editor.org/rfc/rfc5842.html#section-7.2].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#508].
- #
+ # See {508 Loop Detected (WebDAV)}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#508].
class HTTPLoopDetected < HTTPServerError
HAS_BODY = true
end
@@ -1066,15 +630,7 @@ module Net
# Response class for <tt>Not Extended</tt> responses (status code 510).
#
# Further extensions to the request are required for the server to fulfill it.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/510].
- # - {RFC 2774}[https://www.rfc-editor.org/rfc/rfc2774.html#section-7].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#510].
- #
+ # See {510 Not Extended}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#510].
class HTTPNotExtended < HTTPServerError
HAS_BODY = true
end
@@ -1082,15 +638,7 @@ module Net
# Response class for <tt>Network Authentication Required</tt> responses (status code 511).
#
# The client needs to authenticate to gain network access.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/511].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-6].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#511].
- #
+ # See {511 Network Authentication Required}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#511].
class HTTPNetworkAuthenticationRequired < HTTPServerError
HAS_BODY = true
end
diff --git a/lib/net/http/status.rb b/lib/net/http/status.rb
index e70b47d9fb..8db3f7d9e3 100644
--- a/lib/net/http/status.rb
+++ b/lib/net/http/status.rb
@@ -4,7 +4,7 @@ require_relative '../http'
if $0 == __FILE__
require 'open-uri'
- File.foreach(__FILE__) do |line|
+ IO.foreach(__FILE__) do |line|
puts line
break if line.start_with?('end')
end
@@ -16,7 +16,7 @@ if $0 == __FILE__
next if ['(Unused)', 'Unassigned', 'Description'].include?(mes)
puts " #{code} => '#{mes}',"
end
- puts "} # :nodoc:"
+ puts "}"
end
Net::HTTP::STATUS_CODES = {
@@ -55,16 +55,15 @@ Net::HTTP::STATUS_CODES = {
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
- 413 => 'Content Too Large',
+ 413 => 'Payload Too Large',
414 => 'URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Range Not Satisfiable',
417 => 'Expectation Failed',
421 => 'Misdirected Request',
- 422 => 'Unprocessable Content',
+ 422 => 'Unprocessable Entity',
423 => 'Locked',
424 => 'Failed Dependency',
- 425 => 'Too Early',
426 => 'Upgrade Required',
428 => 'Precondition Required',
429 => 'Too Many Requests',
@@ -79,6 +78,6 @@ Net::HTTP::STATUS_CODES = {
506 => 'Variant Also Negotiates',
507 => 'Insufficient Storage',
508 => 'Loop Detected',
- 510 => 'Not Extended (OBSOLETED)',
+ 510 => 'Not Extended',
511 => 'Network Authentication Required',
-} # :nodoc:
+}
diff --git a/lib/net/https.rb b/lib/net/https.rb
index 0f23e1fb13..d46721c82a 100644
--- a/lib/net/https.rb
+++ b/lib/net/https.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
=begin
= net/https -- SSL/TLS enhancement for Net::HTTP.
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 ba2379325f..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.1"
-
Options = {
:proxy => true,
:proxy_http_basic_authentication => true,
@@ -108,7 +104,6 @@ module OpenURI
:ftp_active_mode => false,
:redirect => true,
:encoding => nil,
- :max_redirects => 64,
}
def OpenURI.check_options(options) # :nodoc:
@@ -212,7 +207,6 @@ module OpenURI
end
uri_set = {}
- max_redirects = options[:max_redirects]
buf = nil
while true
redirect = catch(:open_uri_redirect) {
@@ -240,7 +234,6 @@ module OpenURI
uri = redirect
raise "HTTP redirection loop: #{uri}" if uri_set.include? uri.to_s
uri_set[uri.to_s] = true
- raise TooManyRedirects.new("Too many redirects", buf.io) if max_redirects && uri_set.size > max_redirects
else
break
end
@@ -395,9 +388,6 @@ module OpenURI
attr_reader :uri
end
- class TooManyRedirects < HTTPError
- end
-
class Buffer # :nodoc: all
def initialize
@io = StringIO.new
diff --git a/lib/open3.rb b/lib/open3.rb
index 74d00b86d9..9652b27194 100644
--- a/lib/open3.rb
+++ b/lib/open3.rb
@@ -31,189 +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}[rdoc-ref: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@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- #
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Process.spawn;
- # 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.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>]
+ # 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.
#
- # The command line may also contain arguments and options for the command:
+ # Block form:
#
- # Open3.popen3('echo "Foo"') { |i, o, e, t| o.gets }
- # "Foo\n"
+ # 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.
+ # }
#
- # <b>Argument +exe_path+</b>
+ # Non-block form:
#
- # 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:
- #
- # 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
@@ -236,131 +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}[rdoc-ref: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@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ # Open3.popen2 is similar to Open3.popen3 except that it doesn't create a pipe for
+ # the standard error stream.
#
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Process.spawn;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # Block form:
#
- # The single required argument is one of the following:
+ # 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.
+ # }
#
- # - +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.
+ # Non-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"
- #
- # <b>Argument +exe_path+</b>
- #
- # 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"
+ # }
#
+ # Open3.popen2("bc -q") {|i,o,t|
+ # i.puts "obase=13"
+ # i.puts "6 * 9"
+ # p o.gets #=> "42\n"
+ # }
#
- # Related:
- #
- # - 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
@@ -380,130 +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}[rdoc-ref: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@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- #
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Process.spawn;
- # 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):
+ # 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.
+ # }
#
- # # => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577d8a1f0 dead>]
+ # Non-block form:
#
- # 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"
- #
- # <b>Argument +exe_path+</b>
- #
- # 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
@@ -550,100 +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.
+ # Open3.capture3 captures the standard output and the standard error of a command.
#
- # Returns the array <tt>[stdout_s, stderr_s, status]</tt>:
+ # stdout_str, stderr_str, status = Open3.capture3([env,] cmd... [, opts])
#
- # stdout_s, stderr_s, status = Open3.capture3('echo "Foo"')
- # # => ["Foo\n", "", #<Process::Status: pid 2281954 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.
#
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
+ # If <code>opts[:stdin_data]</code> is specified, it is sent to the command's standard input.
#
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
+ # If <code>opts[:binmode]</code> is true, internal pipes are set to binary mode.
#
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Open3.popen3;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ # Examples:
#
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Open3.popen3;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # # dot is a command of graphviz.
+ # graph = <<'End'
+ # digraph g {
+ # a -> b
+ # }
+ # End
+ # drawn_graph, dot_log = Open3.capture3("dot -v", :stdin_data=>graph)
#
- # The hash +options+ is given;
- # two options have local effect in method Open3.capture3:
+ # 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>
#
- # - 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 and
- # 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('echo "Foo"')
- # # => ["Foo\n", "", #<Process::Status: pid 2282092 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.
- #
- # 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:
- #
- # 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>]
+ # # 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
@@ -677,100 +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@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
+ # Open3.capture2 captures the standard output of a command.
#
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Open3.popen3;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ # stdout_str, status = Open3.capture2([env,] cmd... [, opts])
#
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Open3.popen3;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # 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 hash +options+ is given;
- # two options have local effect in method Open3.capture2:
+ # If <code>opts[:stdin_data]</code> is specified, it is sent to the command's standard input.
#
- # - 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>]
- #
- # - If entry <tt>options[:binmode]</tt> exists, the entry is removed and
- # 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.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 command line may also contain arguments and options for the command:
- #
- # 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
@@ -804,100 +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@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Open3.popen3;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- #
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Open3.popen3;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The hash +options+ is given;
- # 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 captures the standard output and the standard error of a command.
#
- # Open3.capture2e('tee', stdin_data: 'Foo')
- # # => ["Foo", #<Process::Status: pid 2371732 exit 0>]
+ # stdout_and_stderr_str, status = Open3.capture2e([env,] cmd... [, opts])
#
- # - If entry <tt>options[:binmode]</tt> exists, the entry is removed and
- # the internal streams are set to binary mode.
+ # 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 single required argument is one of the following:
+ # If <code>opts[:stdin_data]</code> is specified, it is sent to the command's standard input.
#
- # - +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('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>]
- #
- # The command line may also contain arguments and options for the command:
- #
- # Open3.capture2e('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.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
@@ -931,86 +418,48 @@ module Open3
end
module_function :capture2e
- # :call-seq:
- # Open3.pipeline_rw([env, ] *cmds, options = {}) -> [first_stdin, last_stdout, wait_threads]
- #
- # 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 first child, from the caller's +stdin+,
- # or, for the last child, to the caller's +stdout+.
- #
- # The method does not wait for child processes to exit,
- # so the caller must do so.
- #
- # With no block given, returns a 3-element array containing:
- #
- # - The +stdin+ stream of the first child process.
- # - The +stdout+ stream of the last child process.
- # - An array of the wait threads for all of the child processes.
- #
- # Example:
- #
- # first_stdin, last_stdout, wait_threads = Open3.pipeline_rw('sort', 'cat -n')
- # # => [#<IO:fd 20>, #<IO:fd 21>, [#<Process::Waiter:0x000055e8de29ab40 sleep>, #<Process::Waiter:0x000055e8de29a690 sleep>]]
- # first_stdin.puts("foo\nbar\nbaz")
- # first_stdin.close # Send EOF to sort.
- # puts last_stdout.read
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- #
- # Output:
- #
- # 1 bar
- # 2 baz
- # 3 foo
- #
- # With a block given, calls the block with the +stdin+ stream of the first child,
- # the +stdout+ stream of the last child,
- # and an array of the wait processes:
- #
- # Open3.pipeline_rw('sort', 'cat -n') do |first_stdin, last_stdout, wait_threads|
- # first_stdin.puts "foo\nbar\nbaz"
- # first_stdin.close # send EOF to sort.
- # puts last_stdout.read
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- # end
+ # Open3.pipeline_rw starts a list of commands as a pipeline with pipes
+ # which connect to stdin of the first command and stdout of the last command.
#
- # Output:
+ # Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) {|first_stdin, last_stdout, wait_threads|
+ # ...
+ # }
#
- # 1 bar
- # 2 baz
- # 3 foo
+ # first_stdin, last_stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts])
+ # ...
+ # first_stdin.close
+ # last_stdout.close
#
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to 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].
+ # 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)
#
- # 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].
+ # Note that env and opts are optional, as for Process.spawn.
#
- # Each remaining argument in +cmds+ is one of:
+ # The options to pass to Process.spawn are constructed by merging
+ # +opts+, the last hash element of the array, and
+ # specifications for the pipes between each of the commands.
#
- # - 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.
- #
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # Example:
#
+ # Open3.pipeline_rw("tr -dc A-Za-z", "wc -c") {|i, o, ts|
+ # i.puts "All persons more than a mile high to leave the court."
+ # i.close
+ # p o.gets #=> "42\n"
+ # }
+ #
+ # Open3.pipeline_rw("sort", "cat -n") {|stdin, stdout, wait_thrs|
+ # stdin.puts "foo"
+ # stdin.puts "bar"
+ # stdin.puts "baz"
+ # stdin.close # send EOF to sort.
+ # p stdout.read #=> " 1\tbar\n 2\tbaz\n 3\tfoo\n"
+ # }
def pipeline_rw(*cmds, &block)
if Hash === cmds.last
opts = cmds.pop.dup
@@ -1029,77 +478,43 @@ module Open3
end
module_function :pipeline_rw
- # :call-seq:
- # Open3.pipeline_r([env, ] *cmds, options = {}) -> [last_stdout, wait_threads]
+ # Open3.pipeline_r starts a list of commands as a pipeline with a pipe
+ # which connects to stdout of the last command.
#
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
+ # Open3.pipeline_r(cmd1, cmd2, ... [, opts]) {|last_stdout, wait_threads|
+ # ...
+ # }
#
- # - 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+.
+ # last_stdout, wait_threads = Open3.pipeline_r(cmd1, cmd2, ... [, opts])
+ # ...
+ # last_stdout.close
#
- # The method does not wait for child processes to exit,
- # so the caller must do so.
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # With no block given, returns a 2-element array containing:
+ # 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)
#
- # - The +stdout+ stream of the last child process.
- # - An array of the wait threads for all of the child processes.
+ # Note that env and opts are optional, as for Process.spawn.
#
# Example:
#
- # last_stdout, wait_threads = Open3.pipeline_r('ls', 'grep R')
- # # => [#<IO:fd 5>, [#<Process::Waiter:0x000055e8de2f9898 dead>, #<Process::Waiter:0x000055e8de2f94b0 sleep>]]
- # puts last_stdout.read
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- #
- # Output:
- #
- # Rakefile
- # README.md
- #
- # With a block given, calls the block with the +stdout+ stream
- # of the last child process,
- # and an array of the wait processes:
- #
- # Open3.pipeline_r('ls', 'grep R') do |last_stdout, wait_threads|
- # puts last_stdout.read
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- # end
- #
- # Output:
- #
- # Rakefile
- # README.md
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # 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].
- #
- # 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].
+ # Open3.pipeline_r("zcat /var/log/apache2/access.log.*.gz",
+ # [{"LANG"=>"C"}, "grep", "GET /favicon.ico"],
+ # "logresolve") {|o, ts|
+ # o.each_line {|line|
+ # ...
+ # }
+ # }
#
- # Each remaining argument in +cmds+ is one of:
- #
- # - 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.
- #
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # Open3.pipeline_r("yes", "head -10") {|o, ts|
+ # p o.read #=> "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"
+ # p ts[0].value #=> #<Process::Status: pid 24910 SIGPIPE (signal 13)>
+ # p ts[1].value #=> #<Process::Status: pid 24913 exit 0>
+ # }
#
def pipeline_r(*cmds, &block)
if Hash === cmds.last
@@ -1115,82 +530,33 @@ module Open3
end
module_function :pipeline_r
-
- # :call-seq:
- # Open3.pipeline_w([env, ] *cmds, options = {}) -> [first_stdin, wait_threads]
+ # Open3.pipeline_w starts a list of commands as a pipeline with a pipe
+ # which connects to stdin of the first command.
#
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
+ # Open3.pipeline_w(cmd1, cmd2, ... [, opts]) {|first_stdin, wait_threads|
+ # ...
+ # }
#
- # - 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 first child, pipes the caller's +stdout+ to the child's +stdin+.
+ # first_stdin, wait_threads = Open3.pipeline_w(cmd1, cmd2, ... [, opts])
+ # ...
+ # first_stdin.close
#
- # The method does not wait for child processes to exit,
- # so the caller must do so.
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # With no block given, returns a 2-element array containing:
+ # 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)
#
- # - The +stdin+ stream of the first child process.
- # - An array of the wait threads for all of the child processes.
+ # Note that env and opts are optional, as for Process.spawn.
#
# Example:
#
- # first_stdin, wait_threads = Open3.pipeline_w('sort', 'cat -n')
- # # => [#<IO:fd 7>, [#<Process::Waiter:0x000055e8de928278 run>, #<Process::Waiter:0x000055e8de923e80 run>]]
- # first_stdin.puts("foo\nbar\nbaz")
- # first_stdin.close # Send EOF to sort.
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- #
- # Output:
- #
- # 1 bar
- # 2 baz
- # 3 foo
- #
- # With a block given, calls the block with the +stdin+ stream
- # of the first child process,
- # and an array of the wait processes:
- #
- # Open3.pipeline_w('sort', 'cat -n') do |first_stdin, wait_threads|
- # first_stdin.puts("foo\nbar\nbaz")
- # first_stdin.close # Send EOF to sort.
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- # end
- #
- # Output:
- #
- # 1 bar
- # 2 baz
- # 3 foo
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # 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].
- #
- # 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].
- #
- # Each remaining argument in +cmds+ is one of:
- #
- # - 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.
- #
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # Open3.pipeline_w("bzip2 -c", :out=>"/tmp/hello.bz2") {|i, ts|
+ # i.puts "hello"
+ # }
#
def pipeline_w(*cmds, &block)
if Hash === cmds.last
@@ -1207,67 +573,49 @@ module Open3
end
module_function :pipeline_w
- # :call-seq:
- # Open3.pipeline_start([env, ] *cmds, options = {}) -> [wait_threads]
- #
- # 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.
- # - Does not wait for child processes to exit.
- #
- # With no block given, returns an array of the wait threads
- # for all of the child processes.
- #
- # Example:
- #
- # wait_threads = Open3.pipeline_start('ls', 'grep R')
- # # => [#<Process::Waiter:0x000055e8de9d2bb0 run>, #<Process::Waiter:0x000055e8de9d2890 run>]
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- #
- # Output:
- #
- # Rakefile
- # README.md
+ # Open3.pipeline_start starts a list of commands as a pipeline.
+ # No pipes are created for stdin of the first command and
+ # stdout of the last command.
#
- # With a block given, calls the block with an array of the wait processes:
+ # Open3.pipeline_start(cmd1, cmd2, ... [, opts]) {|wait_threads|
+ # ...
+ # }
#
- # Open3.pipeline_start('ls', 'grep R') do |wait_threads|
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- # end
- #
- # Output:
- #
- # Rakefile
- # README.md
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
+ # wait_threads = Open3.pipeline_start(cmd1, cmd2, ... [, opts])
+ # ...
#
- # 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].
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # 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].
+ # 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)
#
- # Each remaining argument in +cmds+ is one of:
+ # Note that env and opts are optional, as for Process.spawn.
#
- # - 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.
+ # Example:
#
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # # Run xeyes in 10 seconds.
+ # Open3.pipeline_start("xeyes") {|ts|
+ # sleep 10
+ # t = ts[0]
+ # Process.kill("TERM", t.pid)
+ # p t.value #=> #<Process::Status: pid 911 SIGTERM (signal 15)>
+ # }
+ #
+ # # Convert pdf to ps and send it to a printer.
+ # # Collect error message of pdftops and lpr.
+ # pdf_file = "paper.pdf"
+ # printer = "printer-name"
+ # err_r, err_w = IO.pipe
+ # Open3.pipeline_start(["pdftops", pdf_file, "-"],
+ # ["lpr", "-P#{printer}"],
+ # :err=>err_w) {|ts|
+ # err_w.close
+ # p err_r.read # error messages of pdftops and lpr.
+ # }
#
def pipeline_start(*cmds, &block)
if Hash === cmds.last
@@ -1285,51 +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:
+ # 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.
#
- # - 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 the child processes to exit.
- # - Returns an array of Process::Status objects (one for each child).
+ # status_list = Open3.pipeline(cmd1, cmd2, ... [, opts])
#
- # Example:
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # wait_threads = Open3.pipeline('ls', 'grep R')
- # # => [#<Process::Status: pid 2139200 exit 0>, #<Process::Status: pid 2139202 exit 0>]
+ # 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)
#
- # Output:
+ # Note that env and opts are optional, as Process.spawn.
#
- # Rakefile
- # README.md
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # 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].
- #
- # 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].
- #
- # Each remaining argument in +cmds+ is one of:
- #
- # - 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.
+ # Example:
#
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # 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>]
+ #
+ # fname = "/usr/share/man/man1/ls.1.gz"
+ # Open3.pipeline(["zcat", fname], "nroff -man", "colcrt")
+ #
+ # # 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 bfcec44ccc..b6b6ee2c9c 100644
--- a/lib/open3/version.rb
+++ b/lib/open3/version.rb
@@ -1,3 +1,3 @@
module Open3
- VERSION = "0.2.1"
+ 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 e44d163d02..0000000000
--- a/lib/prism.rb
+++ /dev/null
@@ -1,99 +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 :DotVisitor, "prism/dot_visitor"
- 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) -> ParseResult
- #
- # Returns a parse result whose value is an array of tokens that closely
- # resembles the return value of Ripper::lex. The main difference is that the
- # `:on_sp` token is not emitted.
- #
- # 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
-
- # :call-seq:
- # Prism::parse_failure?(source, **options) -> bool
- #
- # Returns true if the source parses with errors.
- def self.parse_failure?(source, **options)
- !parse_success?(source, **options)
- end
-
- # :call-seq:
- # Prism::parse_file_failure?(filepath, **options) -> bool
- #
- # Returns true if the file at filepath parses with errors.
- def self.parse_file_failure?(filepath, **options)
- !parse_file_success?(filepath, **options)
- 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 e275fe1dff..0000000000
--- a/lib/prism/debug.rb
+++ /dev/null
@@ -1,200 +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 =
- if node.is_a?(DefNode)
- node.parameters
- elsif node.parameters.is_a?(NumberedParametersNode)
- nil
- else
- node.parameters&.parameters
- end
-
- # 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.is_a?(ImplicitRestNode)),
- *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 daca02f35e..0000000000
--- a/lib/prism/desugar_compiler.rb
+++ /dev/null
@@ -1,207 +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(
- 0,
- read_class.new(*arguments, node.name_loc),
- nil,
- node.operator_loc.slice.chomp("="),
- node.operator_loc.copy(length: node.operator_loc.length - 1),
- nil,
- ArgumentsNode.new(0, [node.value], node.value.location),
- nil,
- nil,
- 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),
- node.operator_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 8324f722a7..0000000000
--- a/lib/prism/ffi.rb
+++ /dev/null
@@ -1,341 +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/libprism.#{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",
- "pm_parse_success_p"
- )
-
- 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_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, data_loc, errors, warnings = loader.load_nodes
- tokens.each { |token,| token.value.force_encoding(loader.encoding) }
-
- ParseResult.new([node, tokens], comments, magic_comments, data_loc, 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
-
- # Mirror the Prism.parse_success? API by using the serialization API.
- def parse_success?(code, **options)
- LibRubyParser.pm_parse_success_p(code, code.bytesize, dump_options(options))
- end
-
- # Mirror the Prism.parse_file_success? API by using the serialization API.
- def parse_file_success?(filepath, **options)
- LibRubyParser::PrismString.with(filepath) do |string|
- parse_success?(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.fetch(:verbose, true) ? 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 2c23933714..0000000000
--- a/lib/prism/lex_compat.rb
+++ /dev/null
@@ -1,892 +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
- last_heredoc_end = 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.
- last_heredoc_end = token.location.end_offset
- 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.
- if previous_token.type == :COMMENT
- # If the comment is at the start of a heredoc: <<HEREDOC # comment
- # then the comment's end_offset is up near the heredoc_beg.
- # This is not the correct offset to use for figuring out if
- # there is trailing whitespace after the last token.
- # Use the greater offset of the two to determine the start of
- # the trailing whitespace.
- start_offset = [previous_token.location.end_offset, last_heredoc_end].compact.max
- end_offset = token.location.start_offset
-
- if 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
- 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.data_loc, 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 8c09632345..0000000000
--- a/lib/prism/node_ext.rb
+++ /dev/null
@@ -1,189 +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
-
- class InterpolatedMatchLastLineNode < Node
- include RegularExpressionOptions
- end
-
- class InterpolatedRegularExpressionNode < Node
- include RegularExpressionOptions
- end
-
- class MatchLastLineNode < Node
- include RegularExpressionOptions
- end
-
- class RegularExpressionNode < Node
- include RegularExpressionOptions
- end
-
- private_constant :RegularExpressionOptions
-
- module HeredocQuery # :nodoc:
- # Returns true if this node was represented as a heredoc in the source code.
- def heredoc?
- opening&.start_with?("<<")
- end
- end
-
- class InterpolatedStringNode < Node
- include HeredocQuery
- end
-
- class InterpolatedXStringNode < Node
- include HeredocQuery
- end
-
- class StringNode < Node
- include HeredocQuery
- end
-
- class XStringNode < Node
- include HeredocQuery
- end
-
- private_constant :HeredocQuery
-
- 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 RationalNode < Node
- # Returns the value of the node as a Ruby Rational.
- def value
- Rational(slice.chomp("r"))
- end
- 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
- # An error class raised when dynamic parts are found while computing a
- # constant path's full name. For example:
- # Foo::Bar::Baz -> does not raise because all parts of the constant path are
- # simple constants
- # var::Bar::Baz -> raises because the first part of the constant path is a
- # local variable
- class DynamicPartsInConstantPathError < StandardError; end
-
- # 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
-
- unless current.is_a?(ConstantReadNode)
- raise DynamicPartsInConstantPathError, "Constant path contains dynamic parts. Cannot compute full name"
- 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 753d72f10b..0000000000
--- a/lib/prism/parse_result.rb
+++ /dev/null
@@ -1,460 +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(byte_offset, length)
- source.byteslice(byte_offset, length)
- end
-
- # Binary search through the offsets to find the line number for the given
- # byte offset.
- def line(byte_offset)
- start_line + find_line(byte_offset)
- end
-
- # Return the byte offset of the start of the line corresponding to the given
- # byte offset.
- def line_start(byte_offset)
- offsets[find_line(byte_offset)]
- end
-
- # Return the column number for the given byte offset.
- def column(byte_offset)
- byte_offset - line_start(byte_offset)
- end
-
- # Return the character offset for the given byte offset.
- def character_offset(byte_offset)
- source.byteslice(0, byte_offset).length
- end
-
- # Return the column number in characters for the given byte offset.
- def character_column(byte_offset)
- character_offset(byte_offset) - character_offset(line_start(byte_offset))
- end
-
- private
-
- # Binary search through the offsets to find the line number for the given
- # byte offset.
- def find_line(byte_offset)
- left = 0
- right = offsets.length - 1
-
- while left <= right
- mid = left + (right - left) / 2
- return mid if offsets[mid] == byte_offset
-
- if offsets[mid] < byte_offset
- 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 character offset from the beginning of the source where this location
- # starts.
- def start_character_offset
- source.character_offset(start_offset)
- end
-
- # The byte offset from the beginning of the source where this location ends.
- def end_offset
- start_offset + length
- end
-
- # The character offset from the beginning of the source where this location
- # ends.
- def end_character_offset
- source.character_offset(end_offset)
- 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_start(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 characters where this location ends from the start of
- # the line.
- def start_character_column
- source.character_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
-
- # The column number in characters where this location ends from the start of
- # the line.
- def end_character_column
- source.character_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
- 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
- # This can only be true for inline comments.
- def trailing?
- false
- end
-
- # Returns a string representation of this comment.
- def inspect
- "#<Prism::EmbDocComment @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
-
- # An optional location that represents the location of the content after the
- # __END__ marker. This content is loaded into the DATA constant when the
- # file being parsed is the main file being executed.
- attr_reader :data_loc
-
- # 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, data_loc, errors, warnings, source)
- @value = value
- @comments = comments
- @magic_comments = magic_comments
- @data_loc = data_loc
- @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, data_loc: data_loc, 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 9f5cea4e20..0000000000
--- a/lib/prism/prism.gemspec
+++ /dev/null
@@ -1,119 +0,0 @@
-# frozen_string_literal: true
-
-Gem::Specification.new do |spec|
- spec.name = "prism"
- spec.version = "0.19.0"
- 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/local_variable_depth.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/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/dot_visitor.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/encoding.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 5bd3088a6a..0000000000
--- a/lib/prism/ripper_compat.rb
+++ /dev/null
@@ -1,207 +0,0 @@
-# frozen_string_literal: true
-
-require "ripper"
-
-module Prism
- # Note: This integration is not finished, and therefore still has many
- # inconsistencies with Ripper. If you'd like to help out, pull requests would
- # be greatly appreciated!
- #
- # 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.
- #
- # To use this class, you treat `Prism::RipperCompat` effectively as you would
- # treat the `Ripper` class.
- class RipperCompat < Visitor
- # 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.failure?
- end
-
- # Parse the source and return the result.
- def parse
- result.magic_comments.each do |magic_comment|
- on_magic_comment(magic_comment.key, magic_comment.value)
- end
-
- if error?
- result.errors.each do |error|
- on_parse_error(error.message)
- end
- else
- result.value.accept(self)
- end
- end
-
- ############################################################################
- # Visitor methods
- ############################################################################
-
- # Visit a CallNode node.
- def visit_call_node(node)
- if !node.message.match?(/^[[:alpha:]_]/) && node.opening_loc.nil? && node.arguments&.arguments&.length == 1
- left = visit(node.receiver)
- right = visit(node.arguments.arguments.first)
-
- bounds(node.location)
- on_binary(left, node.name, right)
- else
- raise NotImplementedError
- end
- end
-
- # Visit a FloatNode node.
- def visit_float_node(node)
- bounds(node.location)
- on_float(node.slice)
- end
-
- # Visit a ImaginaryNode node.
- def visit_imaginary_node(node)
- bounds(node.location)
- on_imaginary(node.slice)
- end
-
- # Visit an IntegerNode node.
- def visit_integer_node(node)
- bounds(node.location)
- on_int(node.slice)
- end
-
- # Visit a RationalNode node.
- def visit_rational_node(node)
- bounds(node.location)
- on_rational(node.slice)
- 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 ProgramNode node.
- def visit_program_node(node)
- statements = visit(node.statements)
- bounds(node.location)
- on_program(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)
- @lineno = location.start_line
- @column = location.start_column
- 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:
-
- alias_method :on_parse_error, :_dispatch1
- alias_method :on_magic_comment, :_dispatch2
-
- (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 befa1d03d7..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 because its output
- # includes not only random bits but also timestamp.
- #
- # 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
-
- # Internal interface to Random; Generate random data _n_ bytes.
private def gen_random(n)
self.bytes(n)
end
@@ -340,20 +221,16 @@ module Random::Formatter
result
end
- # The default character list for #alphanumeric.
ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
-
# Generate a random alphanumeric string.
#
# 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'
#
@@ -361,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.rb b/lib/rdoc.rb
index cf52ce8792..b62c22576d 100644
--- a/lib/rdoc.rb
+++ b/lib/rdoc.rb
@@ -120,17 +120,6 @@ module RDoc
end
end
- ##
- # Seaches and returns the directory for settings.
- #
- # 1. <tt>$HOME/.rdoc</tt> directory, if it exists.
- # 2. The +rdoc+ directory under the path specified by the
- # +XDG_DATA_HOME+ environment variable, if it is set.
- # 3. <tt>$HOME/.local/share/rdoc</tt> directory.
- #
- # Other than the home directory, the containing directory will be
- # created automatically.
-
def self.home
rdoc_dir = begin
File.expand_path('~/.rdoc')
@@ -140,7 +129,6 @@ module RDoc
if File.directory?(rdoc_dir)
rdoc_dir
else
- require 'fileutils'
begin
# XDG
xdg_data_home = ENV["XDG_DATA_HOME"] || File.join(File.expand_path("~"), '.local', 'share')
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 4e011219e8..319bbc02ac 100644
--- a/lib/rdoc/cross_reference.rb
+++ b/lib/rdoc/cross_reference.rb
@@ -131,9 +131,6 @@ class RDoc::CrossReference
@seen = {}
end
- ##
- # Returns a method reference to +name+.
-
def resolve_method name
ref = nil
@@ -226,3 +223,4 @@ class RDoc::CrossReference
end
end
+
diff --git a/lib/rdoc/encoding.rb b/lib/rdoc/encoding.rb
index 67e190f782..cf60badd24 100644
--- a/lib/rdoc/encoding.rb
+++ b/lib/rdoc/encoding.rb
@@ -86,6 +86,17 @@ module RDoc::Encoding
nil
end
+ def self.remove_frozen_string_literal string
+ string =~ /\A(?:#!.*\n)?(.*\n)/
+ first_line = $1
+
+ if first_line =~ /\A# +frozen[-_]string[-_]literal[=:].+$/i
+ string = string.sub first_line, ''
+ end
+
+ string
+ end
+
##
# Detects the encoding of +string+ based on the magic comment
@@ -113,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/pot.rb b/lib/rdoc/generator/pot.rb
index b0b7c07179..bee1133b07 100644
--- a/lib/rdoc/generator/pot.rb
+++ b/lib/rdoc/generator/pot.rb
@@ -81,7 +81,6 @@ class RDoc::Generator::POT
end
end
- # :nodoc:
def class_dir
nil
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 2cc55e03b1..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,
@@ -87,17 +79,6 @@ pre {
border-radius: 0.2em;
}
-em {
- text-decoration-color: rgba(52, 48, 64, 0.25);
- text-decoration-line: underline;
- text-decoration-style: dotted;
-}
-
-strong,
-em {
- background-color: rgba(158, 178, 255, 0.1);
-}
-
table {
margin: 0;
border-spacing: 0;
@@ -200,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;
}
@@ -237,6 +214,7 @@ main h6 {
}
#validator-badges {
+ clear: both;
margin: 1em 1em 2em;
font-size: smaller;
}
@@ -331,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 */
@@ -578,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/markdown/literals.rb b/lib/rdoc/markdown/literals.rb
index c5c15d3100..37659b7ae0 100644
--- a/lib/rdoc/markdown/literals.rb
+++ b/lib/rdoc/markdown/literals.rb
@@ -3,6 +3,7 @@
# :markup: markdown
##
+#--
# This set of literals is for Ruby 1.9 regular expressions and gives full
# unicode support.
#
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 f6eb06da95..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
@@ -138,7 +138,6 @@ class RDoc::Markup::AttributeManager
res
end
- # :nodoc:
def exclusive?(attr)
(attr & @exclusive_bitmap) != 0
end
@@ -156,7 +155,6 @@ class RDoc::Markup::AttributeManager
convert_attrs_word_pair_map(str, attrs, exclusive)
end
- # :nodoc:
def convert_attrs_matching_word_pairs(str, attrs, exclusive)
# first do matching ones
tags = @matching_word_pairs.select { |start, bitmap|
@@ -181,7 +179,6 @@ class RDoc::Markup::AttributeManager
str.delete!(NON_PRINTING_START + NON_PRINTING_END)
end
- # :nodoc:
def convert_attrs_word_pair_map(str, attrs, exclusive)
# then non-matching
unless @word_pair_map.empty? then
@@ -403,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 9daffaabb8..2bac76e838 100644
--- a/lib/rdoc/markup/formatter.rb
+++ b/lib/rdoc/markup/formatter.rb
@@ -90,7 +90,7 @@ class RDoc::Markup::Formatter
def add_regexp_handling_TIDYLINK
@markup.add_regexp_handling(/(?:
- \{[^{}]*\} | # multi-word label
+ \{.*?\} | # multi-word label
\b[^\s{}]+? # single-word label
)
@@ -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/parser.rb b/lib/rdoc/markup/parser.rb
index 9c77048591..0029df7e65 100644
--- a/lib/rdoc/markup/parser.rb
+++ b/lib/rdoc/markup/parser.rb
@@ -218,7 +218,7 @@ class RDoc::Markup::Parser
break if peek_token.first == :BREAK
- data << ' ' if skip :NEWLINE and /#{SPACE_SEPARATED_LETTER_CLASS}\z/o.match?(data)
+ data << ' ' if skip :NEWLINE
else
unget
break
@@ -420,8 +420,6 @@ class RDoc::Markup::Parser
# A simple wrapper of StringScanner that is aware of the current column and lineno
class MyStringScanner
- # :stopdoc:
-
def initialize(input)
@line = @column = 0
@s = StringScanner.new input
@@ -458,8 +456,6 @@ class RDoc::Markup::Parser
def [](i)
@s[i]
end
-
- #:startdoc:
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/table.rb b/lib/rdoc/markup/table.rb
index 27a20f073a..7bcb10aff3 100644
--- a/lib/rdoc/markup/table.rb
+++ b/lib/rdoc/markup/table.rb
@@ -3,21 +3,12 @@
# A section of table
class RDoc::Markup::Table
- # headers of each column
- attr_accessor :header
+ attr_accessor :header, :align, :body
- # alignments of each column
- attr_accessor :align
-
- # body texts of each column
- attr_accessor :body
-
- # Creates new instance
def initialize header, align, body
@header, @align, @body = header, align, body
end
- # :stopdoc:
def == other
self.class == other.class and
@header == other.header and
@@ -29,7 +20,7 @@ class RDoc::Markup::Table
visitor.accept_table @header, @body, @align
end
- def pretty_print q
+ def pretty_print q # :nodoc:
q.group 2, '[Table: ', ']' do
q.group 2, '[Head: ', ']' do
q.seplist @header.zip(@align) do |text, align|
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 91cadf9d16..bf323074de 100644
--- a/lib/rdoc/markup/to_html.rb
+++ b/lib/rdoc/markup/to_html.rb
@@ -61,7 +61,6 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
#
# These methods are used by regexp handling markup added by RDoc::Markup#add_regexp_handling.
- # :nodoc:
URL_CHARACTERS_REGEXP_STR = /[A-Za-z0-9\-._~:\/\?#\[\]@!$&'\(\)*+,;%=]/.source
##
@@ -203,9 +202,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
def accept_paragraph paragraph
@res << "\n<p>"
text = paragraph.text @hard_break
- text = text.gsub(/(#{SPACE_SEPARATED_LETTER_CLASS})?\K\r?\n(?=(?(1)(#{SPACE_SEPARATED_LETTER_CLASS})?))/o) {
- defined?($2) && ' '
- }
+ text = text.gsub(/\r?\n/, ' ')
@res << to_html(text)
@res << "</p>\n"
end
@@ -433,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
@@ -450,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 01831461e3..a9fd09df41 100644
--- a/lib/rdoc/markup/to_html_crossref.rb
+++ b/lib/rdoc/markup/to_html_crossref.rb
@@ -42,7 +42,6 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
@cross_reference = RDoc::CrossReference.new @context
end
- # :nodoc:
def init_link_notation_regexp_handlings
add_regexp_handling_RDOCLINK
@@ -174,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 f471395a3a..4eb36592b7 100644
--- a/lib/rdoc/markup/to_html_snippet.rb
+++ b/lib/rdoc/markup/to_html_snippet.rb
@@ -66,9 +66,6 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
alias accept_rule ignore
- ##
- # Adds +paragraph+ to the output
-
def accept_paragraph paragraph
para = @in_list_entry.last || "<p>"
@@ -285,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/c.rb b/lib/rdoc/parser/c.rb
index d668507dc2..5695bf1acb 100644
--- a/lib/rdoc/parser/c.rb
+++ b/lib/rdoc/parser/c.rb
@@ -575,18 +575,19 @@ class RDoc::Parser::C < RDoc::Parser
table = {}
file_content.scan(%r{
((?>/\*.*?\*/\s*)?)
- ((?:\w+\s+){0,2} VALUE\s+(\w+)
- \s*(?:\([^\)]*\))(?:[^\);]|$))
+ ((?:(?:\w+)\s+)?
+ (?:intern\s+)?VALUE\s+(\w+)
+ \s*(?:\([^)]*\))(?:[^\);]|$))
| ((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+(\w+)\s+(\w+))
| ^\s*\#\s*define\s+(\w+)\s+(\w+)
}xm) do
case
- when name = $3
- table[name] = [:func_def, $1, $2, $~.offset(2)] if !(t = table[name]) || t[0] != :func_def
- when name = $6
- table[name] = [:macro_def, $4, $5, $~.offset(5), $7] if !(t = table[name]) || t[0] == :macro_alias
- when name = $8
- table[name] ||= [:macro_alias, $9]
+ when $1
+ table[$3] = [:func_def, $1, $2, $~.offset(2)] if !table[$3] || table[$3][0] != :func_def
+ when $4
+ table[$6] = [:macro_def, $4, $5, $~.offset(5), $7] if !table[$6] || table[$6][0] == :macro_alias
+ when $8
+ table[$8] ||= [:macro_alias, $9]
end
end
table
@@ -938,13 +939,14 @@ class RDoc::Parser::C < RDoc::Parser
# "/* definition: comment */" form. The literal ':' and '\' characters
# can be escaped with a backslash.
if type.downcase == 'const' then
- if /\A(.+?)?:(?!\S)/ =~ comment.text
- new_definition, new_comment = $1, $'
+ no_match, new_definition, new_comment = comment.text.split(/(\A.*):/)
- if !new_definition # Default to literal C definition
+ if no_match and no_match.empty? then
+ if new_definition.empty? then # Default to literal C definition
new_definition = definition
else
- new_definition = new_definition.gsub(/\\([\\:])/, '\1')
+ new_definition = new_definition.gsub("\:", ":")
+ new_definition = new_definition.gsub("\\", '\\')
end
new_definition.sub!(/\A(\s+)/, '')
@@ -1215,9 +1217,6 @@ class RDoc::Parser::C < RDoc::Parser
@top_level
end
- ##
- # Creates a RDoc::Comment instance.
-
def new_comment text = nil, location = nil, language = nil
RDoc::Comment.new(text, location, language).tap do |comment|
comment.format = @markup
diff --git a/lib/rdoc/parser/changelog.rb b/lib/rdoc/parser/changelog.rb
index a046241870..9245d49376 100644
--- a/lib/rdoc/parser/changelog.rb
+++ b/lib/rdoc/parser/changelog.rb
@@ -216,22 +216,12 @@ class RDoc::Parser::ChangeLog < RDoc::Parser
@top_level
end
- ##
- # The extension for Git commit log
-
module Git
- ##
- # Parses auxiliary info. Currentry `base-url` to expand
- # references is effective.
-
def parse_info(info)
/^\s*base-url\s*=\s*(.*\S)/ =~ info
@base_url = $1
end
- ##
- # Parses the entries in the Git commit logs
-
def parse_entries
entries = []
@@ -254,11 +244,6 @@ class RDoc::Parser::ChangeLog < RDoc::Parser
entries
end
- ##
- # Returns a list of ChangeLog entries as
- # RDoc::Parser::ChangeLog::Git::LogEntry list for the given
- # +entries+.
-
def create_entries entries
# git log entries have no strictly itemized style like the old
# style, just assume Markdown.
@@ -347,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 f6cefd0305..5492f08726 100644
--- a/lib/rdoc/parser/ripper_state_lex.rb
+++ b/lib/rdoc/parser/ripper_state_lex.rb
@@ -1,12 +1,7 @@
# frozen_string_literal: true
require 'ripper'
-##
-# Wrapper for Ripper lex states
-
class RDoc::Parser::RipperStateLex
- # :stopdoc:
-
# TODO: Remove this constants after Ruby 2.4 EOL
RIPPER_HAS_LEX_STATE = Ripper::Filter.method_defined?(:state)
@@ -373,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]
@@ -570,9 +565,6 @@ class RDoc::Parser::RipperStateLex
tk
end
- # :startdoc:
-
- # New lexer for +code+.
def initialize(code)
@buf = []
@heredoc_queue = []
@@ -580,7 +572,6 @@ class RDoc::Parser::RipperStateLex
@tokens = @inner_lex.parse([])
end
- # Returns tokens parsed from +code+.
def self.parse(code)
lex = self.new(code)
tokens = []
@@ -593,7 +584,6 @@ class RDoc::Parser::RipperStateLex
tokens
end
- # Returns +true+ if lex state will be +END+ after +token+.
def self.end?(token)
(token[:state] & EXPR_END)
end
diff --git a/lib/rdoc/parser/ruby.rb b/lib/rdoc/parser/ruby.rb
index 39c3bae4c4..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?$/)
@@ -180,9 +180,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
reset
end
- ##
- # Return +true+ if +tk+ is a newline.
-
def tk_nl?(tk)
:on_nl == tk[:kind] or :on_ignored_nl == tk[:kind]
end
@@ -2137,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 cd27d47dd1..9fc540d317 100644
--- a/lib/rdoc/store.rb
+++ b/lib/rdoc/store.rb
@@ -197,9 +197,6 @@ class RDoc::Store
top_level
end
- ##
- # Sets the parser of +absolute_name+, unless it from a source code file.
-
def update_parser_of_file(absolute_name, parser)
if top_level = @files_hash[absolute_name] then
@text_files_hash[absolute_name] = top_level if top_level.text?
@@ -559,7 +556,9 @@ class RDoc::Store
def load_cache
#orig_enc = @encoding
- @cache = marshal_load(cache_path)
+ File.open cache_path, 'rb' do |io|
+ @cache = Marshal.load io
+ end
load_enc = @cache[:encoding]
@@ -616,7 +615,9 @@ class RDoc::Store
def load_class_data klass_name
file = class_file klass_name
- marshal_load(file)
+ File.open file, 'rb' do |io|
+ Marshal.load io
+ end
rescue Errno::ENOENT => e
error = MissingFileError.new(self, file, klass_name)
error.set_backtrace e.backtrace
@@ -629,10 +630,14 @@ class RDoc::Store
def load_method klass_name, method_name
file = method_file klass_name, method_name
- obj = marshal_load(file)
- obj.store = self
- obj.parent ||= find_class_or_module(klass_name) || load_class(klass_name)
- obj
+ 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
rescue Errno::ENOENT => e
error = MissingFileError.new(self, file, klass_name + method_name)
error.set_backtrace e.backtrace
@@ -645,9 +650,11 @@ class RDoc::Store
def load_page page_name
file = page_file page_name
- obj = marshal_load(file)
- obj.store = self
- obj
+ File.open file, 'rb' do |io|
+ obj = Marshal.load io
+ obj.store = self
+ obj
+ end
rescue Errno::ENOENT => e
error = MissingFileError.new(self, file, page_name)
error.set_backtrace e.backtrace
@@ -969,21 +976,4 @@ 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/text.rb b/lib/rdoc/text.rb
index 9804f81abe..0bc4aba428 100644
--- a/lib/rdoc/text.rb
+++ b/lib/rdoc/text.rb
@@ -10,10 +10,6 @@ require 'strscan'
module RDoc::Text
- ##
- # The language for this text. This affects stripping comments
- # markers.
-
attr_accessor :language
##
@@ -313,10 +309,4 @@ module RDoc::Text
res.join.strip
end
- ##
- # Character class to be separated by a space when concatenating
- # lines.
-
- SPACE_SEPARATED_LETTER_CLASS = /[\p{Nd}\p{Lc}\p{Pc}]|[!-~&&\W]/
-
end
diff --git a/lib/rdoc/token_stream.rb b/lib/rdoc/token_stream.rb
index 19ca7ed248..f428e2400c 100644
--- a/lib/rdoc/token_stream.rb
+++ b/lib/rdoc/token_stream.rb
@@ -112,7 +112,8 @@ module RDoc::TokenStream
# Returns a string representation of the token stream
def tokens_to_s
- (token_stream or return '').compact.map { |token| token[:text] }.join ''
+ token_stream.compact.map { |token| token[:text] }.join ''
end
end
+
diff --git a/lib/rdoc/top_level.rb b/lib/rdoc/top_level.rb
index 3864f66431..b8b6110bb2 100644
--- a/lib/rdoc/top_level.rb
+++ b/lib/rdoc/top_level.rb
@@ -52,9 +52,6 @@ class RDoc::TopLevel < RDoc::Context
@classes_or_modules = []
end
- ##
- # Sets the parser for this toplevel context, also the store.
-
def parser=(val)
@parser = val
@store.update_parser_of_file(absolute_name, val) if @store
@@ -289,3 +286,4 @@ class RDoc::TopLevel < RDoc::Context
end
end
+
diff --git a/lib/rdoc/version.rb b/lib/rdoc/version.rb
index 87842d9847..04322a1970 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.3.1'
+ VERSION = '6.5.0'
end
diff --git a/lib/readline.gemspec b/lib/readline.gemspec
index 9221c29263..3a18f9edb6 100644
--- a/lib/readline.gemspec
+++ b/lib/readline.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = 'readline'
- spec.version = '0.0.4'
+ spec.version = '0.0.3'
spec.authors = ['aycabta']
spec.email = ['aycabta@gmail.com']
diff --git a/lib/readline.rb b/lib/readline.rb
index d1c9d3a955..29cdf3a14f 100644
--- a/lib/readline.rb
+++ b/lib/readline.rb
@@ -1,5 +1,5 @@
begin
- require "readline.#{RbConfig::CONFIG["DLEXT"]}"
+ require 'readline.so'
rescue LoadError
require 'reline' unless defined? Reline
Object.send(:remove_const, :Readline) if Object.const_defined?(:Readline)
diff --git a/lib/reline.rb b/lib/reline.rb
index ddb0224180..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,29 +8,38 @@ require 'reline/key_stroke'
require 'reline/line_editor'
require 'reline/history'
require 'reline/terminfo'
-require 'reline/io'
-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
- # For dialog_proc `key.match?(dialog.name)`
- def match?(sym)
- combined_char.is_a?(Symbol) && combined_char == sym
+ Key = Struct.new('Key', :char, :combined_char, :with_meta) do
+ def match?(other)
+ case other
+ when Reline::Key
+ (other.char.nil? or char.nil? or char == other.char) and
+ (other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and
+ (other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta)
+ when Integer, Symbol
+ (combined_char and combined_char == other) or
+ (combined_char.nil? and char and char == other)
+ else
+ false
+ end
end
+ alias_method :==, :match?
end
CursorPos = Struct.new(:x, :y)
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,
@@ -66,54 +76,50 @@ module Reline
def initialize
self.output = STDOUT
- @mutex = Mutex.new
@dialog_proc_list = {}
yield self
@completion_quote_character = nil
- end
-
- def io_gate
- Reline::IOGate
+ @bracketed_paste_finished = false
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)
@@ -159,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)
@@ -174,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
@@ -206,30 +212,37 @@ module Reline
end
def get_screen_size
- io_gate.get_screen_size
+ Reline::IOGate.get_screen_size
end
Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE = ->() {
# autocomplete
- return unless config.autocompletion
-
- journey_data = completion_journey_data
- return unless journey_data
-
- target = journey_data.list.first
- completed = journey_data.list[journey_data.pointer]
- result = journey_data.list.drop(1)
- pointer = journey_data.pointer - 1
- return if completed.empty? || (result == [completed] && pointer < 0)
-
+ return nil unless config.autocompletion
+ if just_cursor_moving and completion_journey_data.nil?
+ # Auto complete starts only when edited
+ return nil
+ end
+ pre, target, post = retrieve_completion_block(true)
+ if target.nil? or target.empty? or (completion_journey_data&.pointer == -1 and target.size <= 3)
+ return nil
+ end
+ if completion_journey_data and completion_journey_data.list
+ result = completion_journey_data.list.dup
+ result.shift
+ pointer = completion_journey_data.pointer - 1
+ else
+ result = call_completion_proc_with_checking_args(pre, target, post)
+ pointer = nil
+ end
+ if result and result.size == 1 and result[0] == target and pointer != 0
+ result = nil
+ end
target_width = Reline::Unicode.calculate_width(target)
- completed_width = Reline::Unicode.calculate_width(completed)
- if cursor_pos.x <= completed_width - target_width
- # When target is rendered on the line above cursor position
- x = screen_width - completed_width
+ x = cursor_pos.x - target_width
+ if x < 0
+ x = screen_width + x
y = -1
else
- x = [cursor_pos.x - completed_width, 0].max
y = 0
end
cursor_pos_to_render = Reline::CursorPos.new(x, y)
@@ -242,58 +255,47 @@ 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)
- @mutex.synchronize do
- unless confirm_multiline_termination
- raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
- end
-
- io_gate.with_raw_input do
- inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
- end
-
- 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)
- if line_editor.eof?
- line_editor.reset_line
- # Return nil if the input is aborted by C-d.
- nil
- else
- whole_buffer
- end
+ 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)
- @mutex.synchronize do
- io_gate.with_raw_input do
- inner_readline(prompt, add_hist, false)
- end
-
- line = line_editor.line.dup
- line.taint if RUBY_VERSION < '2.7'
- if add_hist and line and line.chomp("\n").size > 0
- Reline::HISTORY << line.chomp("\n")
- end
+ inner_readline(prompt, add_hist, false)
- line_editor.reset_line if line_editor.line.nil?
- line
+ line = line_editor.line.dup
+ line.taint if RUBY_VERSION < '2.7'
+ if add_hist and line and line.chomp("\n").size > 0
+ Reline::HISTORY << line.chomp("\n")
end
+
+ line_editor.reset_line if line_editor.line.nil?
+ line
end
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')
@@ -301,14 +303,10 @@ module Reline
$stderr.sync = true
$stderr.puts "Reline is used by #{Process.pid}"
end
- unless config.test_mode or config.loaded?
- config.read
- io_gate.set_default_key_bindings(config)
- 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?
@@ -324,84 +322,157 @@ module Reline
line_editor.prompt_proc = prompt_proc
line_editor.auto_indent_proc = auto_indent_proc
line_editor.dig_perfect_match_proc = dig_perfect_match_proc
+ line_editor.pre_input_hook = pre_input_hook
+ @dialog_proc_list.each_pair do |name_sym, d|
+ line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
+ end
- # Readline calls pre_input_hook just after printing the first prompt.
- line_editor.print_nomultiline_prompt
- pre_input_hook&.call
-
- unless Reline::IOGate.dumb?
- @dialog_proc_list.each_pair do |name_sym, d|
- line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
- end
+ unless config.test_mode
+ config.read
+ config.reset_default_key_bindings
+ Reline::IOGate.set_default_key_bindings(config)
end
- line_editor.update_dialogs
line_editor.rerender
begin
line_editor.set_signal_handlers
+ prev_pasting_state = false
loop do
+ prev_pasting_state = Reline::IOGate.in_pasting?
read_io(config.keyseq_timeout) { |inputs|
- line_editor.set_pasting_state(io_gate.in_pasting?)
- inputs.each do |key|
- if key.char == :bracketed_paste_start
- text = io_gate.read_bracketed_paste
- line_editor.insert_multiline_text(text)
- line_editor.scroll_into_view
- else
- line_editor.update(key)
- end
+ line_editor.set_pasting_state(Reline::IOGate.in_pasting?)
+ inputs.each { |c|
+ line_editor.input_key(c)
+ line_editor.rerender
+ }
+ if @bracketed_paste_finished
+ line_editor.rerender_all
+ @bracketed_paste_finished = false
end
}
- if line_editor.finished?
- line_editor.render_finished
- break
- else
- line_editor.set_pasting_state(io_gate.in_pasting?)
- line_editor.rerender
+ 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.
- ensure
+ rescue StandardError => e
line_editor.finalize
- io_gate.deprep(otio)
+ Reline::IOGate.deprep(otio)
+ raise e
+ rescue Exception
+ # Including Interrupt
+ line_editor.finalize
+ Reline::IOGate.deprep(otio)
+ raise
end
+
+ line_editor.finalize
+ Reline::IOGate.deprep(otio)
end
- # GNU Readline watis for "keyseq-timeout" milliseconds when the input is
- # ambiguous whether it is matching or matched.
- # If the next character does not arrive within the specified timeout, input
- # is considered as matched.
- # `ESC` is ambiguous because it can be a standalone ESC (matched) or part of
- # `ESC char` or part of CSI sequence (matching).
+ # GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
+ # is followed by a character, and times out and treats it as a standalone
+ # ESC if the second character does not arrive. If the second character
+ # comes before timed out, it is treated as a modifier key with the
+ # meta-property of meta-key, so that it can be distinguished from
+ # multibyte characters with the 8th bit turned on.
+ #
+ # GNU Readline will wait for the 2nd character with "keyseq-timeout"
+ # milli-seconds but wait forever after 3rd characters.
private def read_io(keyseq_timeout, &block)
buffer = []
- status = KeyStroke::MATCHING
loop do
- timeout = status == KeyStroke::MATCHING_MATCHED ? keyseq_timeout.fdiv(1000) : Float::INFINITY
- c = io_gate.getc(timeout)
- if c.nil? || c == -1
- if status == KeyStroke::MATCHING_MATCHED
- status = KeyStroke::MATCHED
- elsif buffer.empty?
- # io_gate is closed and reached EOF
- block.call([Key.new(nil, nil, false)])
- return
- else
- status = KeyStroke::UNMATCHED
- end
+ c = Reline::IOGate.getc
+ if c == -1
+ result = :unmatched
+ @bracketed_paste_finished = true
else
buffer << c
- status = key_stroke.match_status(buffer)
+ result = key_stroke.match_status(buffer)
end
+ case result
+ when :matched
+ expanded = key_stroke.expand(buffer).map{ |expanded_c|
+ Reline::Key.new(expanded_c, expanded_c, false)
+ }
+ block.(expanded)
+ break
+ when :matching
+ if buffer.size == 1
+ case read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
+ when :break then break
+ when :next then next
+ end
+ end
+ when :unmatched
+ if buffer.size == 1 and c == "\e".ord
+ read_escaped_key(keyseq_timeout, c, block)
+ else
+ expanded = buffer.map{ |expanded_c|
+ Reline::Key.new(expanded_c, expanded_c, false)
+ }
+ block.(expanded)
+ end
+ break
+ end
+ end
+ end
- if status == KeyStroke::MATCHED || status == KeyStroke::UNMATCHED
- expanded, rest_bytes = key_stroke.expand(buffer)
- rest_bytes.reverse_each { |c| io_gate.ungetc(c) }
- block.call(expanded)
- return
+ private def read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
+ 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
+ block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
+ else
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
+ end
+ return :break
+ when :matching
+ Reline::IOGate.ungetc(succ_c)
+ return :next
+ when :matched
+ buffer << succ_c
+ expanded = key_stroke.expand(buffer).map{ |expanded_c|
+ Reline::Key.new(expanded_c, expanded_c, false)
+ }
+ block.(expanded)
+ return :break
+ end
+ end
+ end
+
+ private def read_escaped_key(keyseq_timeout, c, block)
+ 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)])
+ else
+ 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
@@ -412,19 +483,19 @@ module Reline
end
private def may_req_ambiguous_char_width
- @ambiguous_width = 2 if io_gate.dumb? || !STDIN.tty? || !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
@@ -460,8 +531,8 @@ module Reline
def_single_delegator :line_editor, :byte_pointer, :point
def_single_delegator :line_editor, :byte_pointer=, :point=
- def self.insert_text(text)
- line_editor.insert_multiline_text(text)
+ def self.insert_text(*args, &block)
+ line_editor.insert_text(*args, &block)
self
end
@@ -487,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`><=;|&{("
@@ -500,7 +571,7 @@ module Reline
end
def self.ungetc(c)
- core.io_gate.ungetc(c)
+ Reline::IOGate.ungetc(c)
end
def self.line_editor
@@ -508,12 +579,22 @@ module Reline
end
end
-
-Reline::IOGate = Reline::IO.decide_io_gate
-
-# Deprecated
-Reline::GeneralIO = Reline::Dumb.new
-
-Reline::Face.load_initial_configs
+require 'reline/general_io'
+io = Reline::GeneralIO
+unless ENV['TERM'] == 'dumb'
+ case RbConfig::CONFIG['host_os']
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
+ require 'reline/windows'
+ tty = (io = Reline::Windows).msys_tty?
+ else
+ tty = $stdout.tty?
+ end
+end
+Reline::IOGate = if tty
+ require 'reline/ansi'
+ Reline::ANSI
+else
+ io
+end
Reline::HISTORY = Reline::History.new(Reline.core.config)
diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb
new file mode 100644
index 0000000000..c40085e50d
--- /dev/null
+++ b/lib/reline/ansi.rb
@@ -0,0 +1,350 @@
+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,
+ 'kcuu1' => :ed_prev_history,
+ 'kcud1' => :ed_next_history,
+ 'kcuf1' => :ed_next_char,
+ 'kcub1' => :ed_prev_char,
+ 'cuu' => :ed_prev_history,
+ 'cud' => :ed_next_history,
+ 'cuf' => :ed_next_char,
+ 'cub' => :ed_prev_char,
+ }
+
+ if Reline::Terminfo.enabled?
+ Reline::Terminfo.setupterm(0, 2)
+ end
+
+ def self.encoding
+ Encoding.default_external
+ end
+
+ def self.win?
+ false
+ end
+
+ 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)
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
+ end
+ {
+ # default bindings
+ [27, 32] => :em_set_mark, # M-<space>
+ [24, 24] => :em_exchange_mark, # C-x C-x
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ 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)
+ 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
+ end.compact.to_h
+
+ key_bindings.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
+ end
+
+ def self.set_default_key_bindings_comprehensive_list(config)
+ {
+ # Console (80x25)
+ [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, # ↓
+ [27, 71, 67] => :ed_next_char, # →
+ [27, 71, 68] => :ed_prev_char, # ←
+
+ # urxvt / exoterm
+ [27, 91, 55, 126] => :ed_move_to_beg, # Home
+ [27, 91, 56, 126] => :ed_move_to_end, # End
+
+ # GNOME
+ [27, 79, 72] => :ed_move_to_beg, # Home
+ [27, 79, 70] => :ed_move_to_end, # End
+ # 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, # →
+ [27, 79, 68] => :ed_prev_char, # ←
+ }.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
+ end
+
+ @@input = STDIN
+ def self.input=(val)
+ @@input = val
+ end
+
+ @@output = STDOUT
+ def self.output=(val)
+ @@output = val
+ end
+
+ @@buf = []
+ def self.inner_getc
+ unless @@buf.empty?
+ return @@buf.shift
+ end
+ until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
+ Reline.core.line_editor.resize
+ end
+ (c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
+ rescue Errno::EIO
+ # Maybe the I/O has been closed.
+ nil
+ rescue Errno::ENOTTY
+ nil
+ end
+
+ @@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
+ buffer = String.new(encoding: Encoding::ASCII_8BIT)
+ 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
+ elsif END_BRACKETED_PASTE == buffer
+ @@in_bracketed_paste_mode = false
+ ungetc(-1)
+ return inner_getc
+ end
+ 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
+ end
+
+ def self.getc
+ if Reline.core.config.enable_bracketed_paste
+ getc_with_bracketed_paste
+ else
+ inner_getc
+ end
+ end
+
+ def self.in_pasting?
+ @@in_bracketed_paste_mode or (not Reline::IOGate.empty_buffer?)
+ end
+
+ def self.empty_buffer?
+ unless @@buf.empty?
+ return false
+ end
+ !@@input.wait_readable(0)
+ end
+
+ def self.ungetc(c)
+ @@buf.unshift(c)
+ end
+
+ def self.retrieve_keybuffer
+ begin
+ return unless @@input.wait_readable(0.001)
+ str = @@input.read_nonblock(1024)
+ str.bytes.each do |c|
+ @@buf.push(c)
+ end
+ rescue EOFError
+ end
+ end
+
+ def self.get_screen_size
+ s = @@input.winsize
+ return s if s[0] > 0 && s[1] > 0
+ s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
+ return s if s[0] > 0 && s[1] > 0
+ [24, 80]
+ rescue Errno::ENOTTY
+ [24, 80]
+ end
+
+ def self.set_screen_size(rows, columns)
+ @@input.winsize = [rows, columns]
+ self
+ rescue Errno::ENOTTY
+ self
+ end
+
+ def self.cursor_pos
+ begin
+ res = +''
+ m = nil
+ @@input.raw do |stdin|
+ @@output << "\e[6n"
+ @@output.flush
+ loop do
+ c = stdin.getc
+ next if c.nil?
+ res << c
+ m = res.match(/\e\[(?<row>\d+);(?<column>\d+)R/)
+ break if m
+ end
+ (m.pre_match + m.post_match).chars.reverse_each do |ch|
+ stdin.ungetc ch
+ end
+ end
+ column = m[:column].to_i - 1
+ row = m[:row].to_i - 1
+ rescue Errno::ENOTTY
+ begin
+ buf = @@output.pread(@@output.pos, 0)
+ row = buf.count("\n")
+ column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
+ rescue Errno::ESPIPE
+ # Just returns column 1 for ambiguous width because this I/O is not
+ # tty and can't seek.
+ row = 0
+ column = 1
+ end
+ end
+ Reline::CursorPos.new(column, row)
+ end
+
+ def self.move_cursor_column(x)
+ @@output.write "\e[#{x + 1}G"
+ end
+
+ def self.move_cursor_up(x)
+ if x > 0
+ @@output.write "\e[#{x}A"
+ elsif x < 0
+ move_cursor_down(-x)
+ end
+ end
+
+ def self.move_cursor_down(x)
+ if x > 0
+ @@output.write "\e[#{x}B"
+ elsif x < 0
+ move_cursor_up(-x)
+ end
+ end
+
+ def self.hide_cursor
+ if Reline::Terminfo.enabled?
+ begin
+ @@output.write Reline::Terminfo.tigetstr('civis')
+ rescue Reline::Terminfo::TerminfoError
+ # civis is undefined
+ end
+ else
+ # ignored
+ end
+ end
+
+ def self.show_cursor
+ if Reline::Terminfo.enabled?
+ begin
+ @@output.write Reline::Terminfo.tigetstr('cnorm')
+ rescue Reline::Terminfo::TerminfoError
+ # cnorm is undefined
+ end
+ else
+ # ignored
+ end
+ end
+
+ def self.erase_after_cursor
+ @@output.write "\e[K"
+ end
+
+ def self.scroll_down(x)
+ return if x.zero?
+ @@output.write "\e[#{x}S"
+ end
+
+ def self.clear_screen
+ @@output.write "\e[2J"
+ @@output.write "\e[1;1H"
+ end
+
+ @@old_winch_handler = nil
+ def self.set_winch_handler(&handler)
+ @@old_winch_handler = Signal.trap('WINCH', &handler)
+ end
+
+ def self.prep
+ retrieve_keybuffer
+ nil
+ end
+
+ def self.deprep(otio)
+ Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
+ end
+end
diff --git a/lib/reline/config.rb b/lib/reline/config.rb
index 6aa6ba8d94..5ba269258f 100644
--- a/lib/reline/config.rb
+++ b/lib/reline/config.rb
@@ -8,12 +8,31 @@ class Reline::Config
end
VARIABLE_NAMES = %w{
+ bind-tty-special-chars
+ blink-matching-paren
+ byte-oriented
completion-ignore-case
convert-meta
disable-completion
+ enable-keypad
+ expand-tilde
+ history-preserve-point
history-size
+ horizontal-scroll-mode
+ input-meta
keyseq-timeout
+ mark-directories
+ mark-modified-lines
+ mark-symlinked-directories
+ match-hidden-files
+ meta-flag
+ output-meta
+ page-completions
+ prefer-visible-bell
+ print-completions-horizontally
show-all-if-ambiguous
+ show-all-if-unmodified
+ visible-stats
show-mode-in-prompt
vi-cmd-mode-string
vi-ins-mode-string
@@ -29,31 +48,20 @@ class Reline::Config
attr_accessor :autocompletion
def initialize
- reset_variables
- end
-
- def reset
- if editing_mode_is?(:vi_command)
- @editing_mode_label = :vi_insert
- end
- @oneshot_key_bindings.clear
- end
-
- def reset_variables
- @additional_key_bindings = { # from inputrc
- emacs: Reline::KeyActor::Base.new,
- vi_insert: Reline::KeyActor::Base.new,
- vi_command: Reline::KeyActor::Base.new
- }
- @oneshot_key_bindings = Reline::KeyActor::Base.new
+ @additional_key_bindings = {} # from inputrc
+ @additional_key_bindings[:emacs] = {}
+ @additional_key_bindings[:vi_insert] = {}
+ @additional_key_bindings[:vi_command] = {}
+ @oneshot_key_bindings = {}
+ @skip_section = nil
+ @if_stack = nil
@editing_mode_label = :emacs
@keymap_label = :emacs
@keymap_prefix = []
- @default_key_bindings = {
- emacs: Reline::KeyActor::Base.new(Reline::KeyActor::EMACS_MAPPING),
- vi_insert: Reline::KeyActor::Base.new(Reline::KeyActor::VI_INSERT_MAPPING),
- vi_command: Reline::KeyActor::Base.new(Reline::KeyActor::VI_COMMAND_MAPPING)
- }
+ @key_actors = {}
+ @key_actors[:emacs] = Reline::KeyActor::Emacs.new
+ @key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
+ @key_actors[:vi_command] = Reline::KeyActor::ViCommand.new
@vi_cmd_mode_string = '(cmd)'
@vi_ins_mode_string = '(ins)'
@emacs_mode_string = '@'
@@ -62,15 +70,22 @@ class Reline::Config
@keyseq_timeout = 500
@test_mode = false
@autocompletion = false
- @convert_meta = seven_bit_encoding?(Reline::IOGate.encoding)
- @loaded = false
- @enable_bracketed_paste = true
- @show_mode_in_prompt = false
- @default_inputrc_path = nil
+ @convert_meta = true if seven_bit_encoding?(Reline::IOGate.encoding)
+ end
+
+ def reset
+ if editing_mode_is?(:vi_command)
+ @editing_mode_label = :vi_insert
+ end
+ @additional_key_bindings.keys.each do |key|
+ @additional_key_bindings[key].clear
+ end
+ @oneshot_key_bindings.clear
+ reset_default_key_bindings
end
def editing_mode
- @default_key_bindings[@editing_mode_label]
+ @key_actors[@editing_mode_label]
end
def editing_mode=(val)
@@ -78,15 +93,11 @@ 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
- @default_key_bindings[@keymap_label]
- end
-
- def loaded?
- @loaded
+ @key_actors[@keymap_label]
end
def inputrc_path
@@ -120,7 +131,6 @@ class Reline::Config
end
def read(file = nil)
- @loaded = true
file ||= default_inputrc_path
begin
if file.respond_to?(:readlines)
@@ -141,14 +151,14 @@ class Reline::Config
def key_bindings
# The key bindings for each editing mode will be overwritten by the user-defined ones.
- Reline::KeyActor::Composite.new([@oneshot_key_bindings, @additional_key_bindings[@editing_mode_label], @default_key_bindings[@editing_mode_label]])
+ kb = @key_actors[@editing_mode_label].default_key_bindings.dup
+ kb.merge!(@additional_key_bindings[@editing_mode_label])
+ kb.merge!(@oneshot_key_bindings)
+ kb
end
def add_oneshot_key_binding(keystroke, target)
- # IRB sets invalid keystroke [Reline::Key]. We should ignore it.
- return unless keystroke.all? { |c| c.is_a?(Integer) }
-
- @oneshot_key_bindings.add(keystroke, target)
+ @oneshot_key_bindings[keystroke] = target
end
def reset_oneshot_key_bindings
@@ -156,11 +166,17 @@ class Reline::Config
end
def add_default_key_binding_by_keymap(keymap, keystroke, target)
- @default_key_bindings[keymap].add(keystroke, target)
+ @key_actors[keymap].default_key_bindings[keystroke] = target
end
def add_default_key_binding(keystroke, target)
- add_default_key_binding_by_keymap(@keymap_label, keystroke, target)
+ @key_actors[@keymap_label].default_key_bindings[keystroke] = target
+ end
+
+ def reset_default_key_bindings
+ @key_actors.values.each do |ka|
+ ka.reset_default_key_bindings
+ end
end
def read_lines(lines, file = nil)
@@ -174,7 +190,9 @@ class Reline::Config
end
end
end
- if_stack = []
+ conditions = [@skip_section, @if_stack]
+ @skip_section = nil
+ @if_stack = []
lines.each_with_index do |line, no|
next if line.match(/\A\s*#/)
@@ -183,67 +201,62 @@ class Reline::Config
line = line.chomp.lstrip
if line.start_with?('$')
- handle_directive(line[1..-1], file, no, if_stack)
+ handle_directive(line[1..-1], file, no)
next
end
- next if if_stack.any? { |_no, skip| skip }
+ next if @skip_section
case line
- when /^set +([^ ]+) +(.+)/i
- # value ignores everything after a space, raw_value does not.
- var, value, raw_value = $1.downcase, $2.partition(' ').first, $2
- bind_variable(var, value, raw_value)
+ when /^set +([^ ]+) +([^ ]+)/i
+ var, value = $1.downcase, $2
+ bind_variable(var, value)
next
when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
key, func_name = $1, $2
- func_name = func_name.split.first
keystroke, func = bind_key(key, func_name)
next unless keystroke
- @additional_key_bindings[@keymap_label].add(@keymap_prefix + keystroke, func)
+ @additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
end
end
- unless if_stack.empty?
- raise InvalidInputrc, "#{file}:#{if_stack.last[0]}: unclosed if"
+ unless @if_stack.empty?
+ raise InvalidInputrc, "#{file}:#{@if_stack.last[1]}: unclosed if"
end
+ ensure
+ @skip_section, @if_stack = conditions
end
- def handle_directive(directive, file, no, if_stack)
+ def handle_directive(directive, file, no)
directive, args = directive.split(' ')
case directive
when 'if'
condition = false
case args
- when /^mode=(vi|emacs)$/i
- mode = $1.downcase
- # NOTE: mode=vi means vi-insert mode
- mode = 'vi_insert' if mode == 'vi'
- if @editing_mode_label == mode.to_sym
- condition = true
- end
+ when 'mode'
when 'term'
when 'version'
else # application name
condition = true if args == 'Ruby'
condition = true if args == 'Reline'
end
- if_stack << [no, !condition]
+ @if_stack << [file, no, @skip_section]
+ @skip_section = !condition
when 'else'
- if if_stack.empty?
+ if @if_stack.empty?
raise InvalidInputrc, "#{file}:#{no}: unmatched else"
end
- if_stack.last[1] = !if_stack.last[1]
+ @skip_section = !@skip_section
when 'endif'
- if if_stack.empty?
+ if @if_stack.empty?
raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
end
- if_stack.pop
+ @skip_section = @if_stack.pop
when 'include'
- read(File.expand_path(args))
+ read(args)
end
end
- def bind_variable(name, value, raw_value)
+ def bind_variable(name, value)
case name
when 'history-size'
begin
@@ -251,8 +264,24 @@ class Reline::Config
rescue ArgumentError
@history_size = 500
end
+ when 'bell-style'
+ @bell_style =
+ case value
+ when 'none', 'off'
+ :none
+ when 'audible', 'on'
+ :audible
+ when 'visible'
+ :visible
+ else
+ :audible
+ end
+ when 'comment-begin'
+ @comment_begin = value.dup
+ when 'completion-query-items'
+ @completion_query_items = value.to_i
when 'isearch-terminators'
- @isearch_terminators = retrieve_string(raw_value)
+ @isearch_terminators = retrieve_string(value)
when 'editing-mode'
case value
when 'emacs'
@@ -294,11 +323,11 @@ class Reline::Config
@show_mode_in_prompt = false
end
when 'vi-cmd-mode-string'
- @vi_cmd_mode_string = retrieve_string(raw_value)
+ @vi_cmd_mode_string = retrieve_string(value)
when 'vi-ins-mode-string'
- @vi_ins_mode_string = retrieve_string(raw_value)
+ @vi_ins_mode_string = retrieve_string(value)
when 'emacs-mode-string'
- @emacs_mode_string = retrieve_string(raw_value)
+ @emacs_mode_string = retrieve_string(value)
when *VARIABLE_NAMES then
variable_name = :"@#{name.tr(?-, ?_)}"
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
@@ -366,11 +395,6 @@ class Reline::Config
ret
end
- def reload
- reset_variables
- read
- end
-
private def seven_bit_encoding?(encoding)
encoding == Encoding::US_ASCII
end
diff --git a/lib/reline/face.rb b/lib/reline/face.rb
deleted file mode 100644
index 5b4464a623..0000000000
--- a/lib/reline/face.rb
+++ /dev/null
@@ -1,199 +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 reconfigure
- @definition.each_value do |values|
- values.delete(:escape_sequence)
- values[:escape_sequence] = format_to_sgr(values.to_a).freeze
- end
- 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)
- if Reline::Face.truecolor?
- sgr_rgb_truecolor(key, value)
- else
- sgr_rgb_256color(key, value)
- end
- end
-
- def sgr_rgb_truecolor(key, value)
- case key
- when :foreground
- "38;2;"
- when :background
- "48;2;"
- end + value[1, 6].scan(/../).map(&:hex).join(";")
- end
-
- def sgr_rgb_256color(key, value)
- # 256 colors are
- # 0..15: standard colors, high intensity colors
- # 16..232: 216 colors (R, G, B each 6 steps)
- # 233..255: grayscale colors (24 steps)
- # This methods converts rgb_expression to 216 colors
- rgb = value[1, 6].scan(/../).map(&:hex)
- # Color steps are [0, 95, 135, 175, 215, 255]
- r, g, b = rgb.map { |v| v <= 95 ? v / 48 : (v - 35) / 40 }
- color = (16 + 36 * r + 6 * g + b)
- case key
- when :foreground
- "38;5;#{color}"
- when :background
- "48;5;#{color}"
- end
- 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.truecolor?
- @force_truecolor || %w[truecolor 24bit].include?(ENV['COLORTERM'])
- end
-
- def self.force_truecolor
- @force_truecolor = true
- @configs&.each_value(&:reconfigure)
- end
-
- 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: :bright_white, background: :gray
- conf.define :enhanced, foreground: :black, background: :white
- conf.define :scrollbar, foreground: :white, background: :gray
- 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
new file mode 100644
index 0000000000..92c76cbba1
--- /dev/null
+++ b/lib/reline/general_io.rb
@@ -0,0 +1,109 @@
+require 'timeout'
+require 'io/wait'
+
+class Reline::GeneralIO
+ def self.reset(encoding: nil)
+ @@pasting = false
+ @@encoding = encoding
+ end
+
+ def self.encoding
+ if defined?(@@encoding)
+ @@encoding
+ elsif RUBY_PLATFORM =~ /mswin|mingw/
+ Encoding::UTF_8
+ else
+ Encoding::default_external
+ end
+ end
+
+ def self.win?
+ false
+ end
+
+ def self.set_default_key_bindings(_)
+ end
+
+ @@buf = []
+ @@input = STDIN
+
+ def self.input=(val)
+ @@input = val
+ end
+
+ def self.getc
+ unless @@buf.empty?
+ return @@buf.shift
+ end
+ c = nil
+ loop do
+ result = @@input.wait_readable(0.1)
+ next if result.nil?
+ c = @@input.read(1)
+ break
+ end
+ c&.ord
+ end
+
+ def self.ungetc(c)
+ @@buf.unshift(c)
+ end
+
+ def self.get_screen_size
+ [1, 1]
+ end
+
+ def self.cursor_pos
+ Reline::CursorPos.new(1, 1)
+ end
+
+ def self.hide_cursor
+ end
+
+ def self.show_cursor
+ end
+
+ def self.move_cursor_column(val)
+ end
+
+ def self.move_cursor_up(val)
+ end
+
+ def self.move_cursor_down(val)
+ end
+
+ def self.erase_after_cursor
+ end
+
+ def self.scroll_down(val)
+ end
+
+ def self.clear_screen
+ end
+
+ def self.set_screen_size(rows, columns)
+ end
+
+ def self.set_winch_handler(&handler)
+ end
+
+ @@pasting = false
+
+ def self.in_pasting?
+ @@pasting
+ end
+
+ def self.start_pasting
+ @@pasting = true
+ end
+
+ def self.finish_pasting
+ @@pasting = false
+ end
+
+ def self.prep
+ end
+
+ def self.deprep(otio)
+ end
+end
diff --git a/lib/reline/history.rb b/lib/reline/history.rb
index 3f3b65fea6..7a1ed6b90b 100644
--- a/lib/reline/history.rb
+++ b/lib/reline/history.rb
@@ -62,7 +62,7 @@ class Reline::History < Array
private def check_index(index)
index += size if index < 0
if index < -2147483648 or 2147483647 < index
- raise RangeError.new("integer #{index} too big to convert to 'int'")
+ raise RangeError.new("integer #{index} too big to convert to `int'")
end
# If history_size is negative, history size is unlimited.
if @config.history_size.positive?
diff --git a/lib/reline/io.rb b/lib/reline/io.rb
deleted file mode 100644
index c1dd1a56c8..0000000000
--- a/lib/reline/io.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-
-module Reline
- class IO
- RESET_COLOR = "\e[0m"
-
- def self.decide_io_gate
- if ENV['TERM'] == 'dumb'
- Reline::Dumb.new
- else
- require 'reline/io/ansi'
-
- case RbConfig::CONFIG['host_os']
- when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
- require 'reline/io/windows'
- io = Reline::Windows.new
- if io.msys_tty?
- Reline::ANSI.new
- else
- io
- end
- else
- Reline::ANSI.new
- end
- end
- end
-
- def dumb?
- false
- end
-
- def win?
- false
- end
-
- def reset_color_sequence
- self.class::RESET_COLOR
- end
- end
-end
-
-require 'reline/io/dumb'
diff --git a/lib/reline/io/ansi.rb b/lib/reline/io/ansi.rb
deleted file mode 100644
index a730a953f7..0000000000
--- a/lib/reline/io/ansi.rb
+++ /dev/null
@@ -1,372 +0,0 @@
-require 'io/console'
-require 'io/wait'
-
-class Reline::ANSI < Reline::IO
- 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, {}],
- }
-
- if Reline::Terminfo.enabled?
- Reline::Terminfo.setupterm(0, 2)
- end
-
- def initialize
- @input = STDIN
- @output = STDOUT
- @buf = []
- @old_winch_handler = nil
- end
-
- def encoding
- Encoding.default_external
- end
-
- def set_default_key_bindings(config, allow_terminfo: true)
- set_bracketed_paste_key_bindings(config)
- set_default_key_bindings_ansi_cursor(config)
- if allow_terminfo && Reline::Terminfo.enabled?
- set_default_key_bindings_terminfo(config)
- else
- set_default_key_bindings_comprehensive_list(config)
- end
- {
- [27, 91, 90] => :completion_journey_up, # S-Tab
- }.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)
- end
- {
- # default bindings
- [27, 32] => :em_set_mark, # M-<space>
- [24, 24] => :em_exchange_mark, # C-x C-x
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- end
- end
-
- def set_bracketed_paste_key_bindings(config)
- [:emacs, :vi_insert, :vi_command].each do |keymap|
- config.add_default_key_binding_by_keymap(keymap, START_BRACKETED_PASTE.bytes, :bracketed_paste_start)
- end
- end
-
- def 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 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 ]
- rescue Reline::Terminfo::TerminfoError
- # capname is undefined
- end
- end.compact.to_h
-
- key_bindings.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
- end
-
- def set_default_key_bindings_comprehensive_list(config)
- {
- # xterm
- [27, 91, 51, 126] => :key_delete, # kdch1
- [27, 91, 53, 126] => :ed_search_prev_history, # kpp
- [27, 91, 54, 126] => :ed_search_next_history, # knp
-
- # Console (80x25)
- [27, 91, 49, 126] => :ed_move_to_beg, # Home
- [27, 91, 52, 126] => :ed_move_to_end, # End
-
- # KDE
- # Del is 0x08
- [27, 71, 65] => :ed_prev_history, # ↑
- [27, 71, 66] => :ed_next_history, # ↓
- [27, 71, 67] => :ed_next_char, # →
- [27, 71, 68] => :ed_prev_char, # ←
-
- # urxvt / exoterm
- [27, 91, 55, 126] => :ed_move_to_beg, # Home
- [27, 91, 56, 126] => :ed_move_to_end, # End
-
- # GNOME
- [27, 79, 72] => :ed_move_to_beg, # Home
- [27, 79, 70] => :ed_move_to_end, # End
- # Del is 0x08
- # Arrow keys are the same of KDE
-
- [27, 79, 65] => :ed_prev_history, # ↑
- [27, 79, 66] => :ed_next_history, # ↓
- [27, 79, 67] => :ed_next_char, # →
- [27, 79, 68] => :ed_prev_char, # ←
- }.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
- end
-
- def input=(val)
- @input = val
- end
-
- def output=(val)
- @output = val
- end
-
- def with_raw_input
- if @input.tty?
- @input.raw(intr: true) { yield }
- else
- yield
- end
- end
-
- def inner_getc(timeout_second)
- unless @buf.empty?
- return @buf.shift
- end
- until @input.wait_readable(0.01)
- timeout_second -= 0.01
- return nil if timeout_second <= 0
-
- Reline.core.line_editor.handle_signal
- end
- c = @input.getbyte
- (c == 0x16 && @input.tty? && @input.raw(min: 0, time: 0, &:getbyte)) || c
- rescue Errno::EIO
- # Maybe the I/O has been closed.
- nil
- end
-
- START_BRACKETED_PASTE = String.new("\e[200~", encoding: Encoding::ASCII_8BIT)
- END_BRACKETED_PASTE = String.new("\e[201~", encoding: Encoding::ASCII_8BIT)
- def read_bracketed_paste
- buffer = String.new(encoding: Encoding::ASCII_8BIT)
- until buffer.end_with?(END_BRACKETED_PASTE)
- c = inner_getc(Float::INFINITY)
- break unless c
- buffer << c
- end
- string = buffer.delete_suffix(END_BRACKETED_PASTE).force_encoding(encoding)
- string.valid_encoding? ? string : ''
- end
-
- # if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
- def getc(timeout_second)
- inner_getc(timeout_second)
- end
-
- def in_pasting?
- not empty_buffer?
- end
-
- def empty_buffer?
- unless @buf.empty?
- return false
- end
- !@input.wait_readable(0)
- end
-
- def ungetc(c)
- @buf.unshift(c)
- end
-
- def retrieve_keybuffer
- begin
- return unless @input.wait_readable(0.001)
- str = @input.read_nonblock(1024)
- str.bytes.each do |c|
- @buf.push(c)
- end
- rescue EOFError
- end
- end
-
- def get_screen_size
- s = @input.winsize
- return s if s[0] > 0 && s[1] > 0
- s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
- return s if s[0] > 0 && s[1] > 0
- [24, 80]
- rescue Errno::ENOTTY, Errno::ENODEV
- [24, 80]
- end
-
- def set_screen_size(rows, columns)
- @input.winsize = [rows, columns]
- self
- rescue Errno::ENOTTY, Errno::ENODEV
- self
- end
-
- def cursor_pos
- if both_tty?
- res = +''
- m = nil
- @input.raw do |stdin|
- @output << "\e[6n"
- @output.flush
- loop do
- c = stdin.getc
- next if c.nil?
- res << c
- m = res.match(/\e\[(?<row>\d+);(?<column>\d+)R/)
- break if m
- end
- (m.pre_match + m.post_match).chars.reverse_each do |ch|
- stdin.ungetc ch
- end
- end
- column = m[:column].to_i - 1
- row = m[:row].to_i - 1
- else
- begin
- buf = @output.pread(@output.pos, 0)
- row = buf.count("\n")
- column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
- rescue Errno::ESPIPE, IOError
- # Just returns column 1 for ambiguous width because this I/O is not
- # tty and can't seek.
- row = 0
- column = 1
- end
- end
- Reline::CursorPos.new(column, row)
- end
-
- def both_tty?
- @input.tty? && @output.tty?
- end
-
- def move_cursor_column(x)
- @output.write "\e[#{x + 1}G"
- end
-
- def move_cursor_up(x)
- if x > 0
- @output.write "\e[#{x}A"
- elsif x < 0
- move_cursor_down(-x)
- end
- end
-
- def move_cursor_down(x)
- if x > 0
- @output.write "\e[#{x}B"
- elsif x < 0
- move_cursor_up(-x)
- end
- end
-
- def hide_cursor
- seq = "\e[?25l"
- if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
- begin
- seq = Reline::Terminfo.tigetstr('civis')
- rescue Reline::Terminfo::TerminfoError
- # civis is undefined
- end
- end
- @output.write seq
- end
-
- def show_cursor
- seq = "\e[?25h"
- if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
- begin
- seq = Reline::Terminfo.tigetstr('cnorm')
- rescue Reline::Terminfo::TerminfoError
- # cnorm is undefined
- end
- end
- @output.write seq
- end
-
- def erase_after_cursor
- @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 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
- end
-
- def clear_screen
- @output.write "\e[2J"
- @output.write "\e[1;1H"
- end
-
- def set_winch_handler(&handler)
- @old_winch_handler = Signal.trap('WINCH', &handler)
- @old_cont_handler = Signal.trap('CONT') do
- @input.raw!(intr: true) if @input.tty?
- # Rerender the screen. Note that screen size might be changed while suspended.
- handler.call
- end
- rescue ArgumentError
- # Signal.trap may raise an ArgumentError if the platform doesn't support the signal.
- end
-
- def prep
- # Enable bracketed paste
- @output.write "\e[?2004h" if Reline.core.config.enable_bracketed_paste && both_tty?
- retrieve_keybuffer
- nil
- end
-
- def deprep(otio)
- # Disable bracketed paste
- @output.write "\e[?2004l" if Reline.core.config.enable_bracketed_paste && both_tty?
- Signal.trap('WINCH', @old_winch_handler) if @old_winch_handler
- Signal.trap('CONT', @old_cont_handler) if @old_cont_handler
- end
-end
diff --git a/lib/reline/io/dumb.rb b/lib/reline/io/dumb.rb
deleted file mode 100644
index 6ed69ffdfa..0000000000
--- a/lib/reline/io/dumb.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-require 'io/wait'
-
-class Reline::Dumb < Reline::IO
- RESET_COLOR = '' # Do not send color reset sequence
-
- def initialize(encoding: nil)
- @input = STDIN
- @buf = []
- @pasting = false
- @encoding = encoding
- @screen_size = [24, 80]
- end
-
- def dumb?
- true
- end
-
- def encoding
- if @encoding
- @encoding
- elsif RUBY_PLATFORM =~ /mswin|mingw/
- Encoding::UTF_8
- else
- Encoding::default_external
- end
- end
-
- def set_default_key_bindings(_)
- end
-
- def input=(val)
- @input = val
- end
-
- def with_raw_input
- yield
- end
-
- def getc(_timeout_second)
- unless @buf.empty?
- return @buf.shift
- end
- c = nil
- loop do
- Reline.core.line_editor.handle_signal
- result = @input.wait_readable(0.1)
- next if result.nil?
- c = @input.read(1)
- break
- end
- c&.ord
- end
-
- def ungetc(c)
- @buf.unshift(c)
- end
-
- def get_screen_size
- @screen_size
- end
-
- def cursor_pos
- Reline::CursorPos.new(1, 1)
- end
-
- def hide_cursor
- end
-
- def show_cursor
- end
-
- def move_cursor_column(val)
- end
-
- def move_cursor_up(val)
- end
-
- def move_cursor_down(val)
- end
-
- def erase_after_cursor
- end
-
- def scroll_down(val)
- end
-
- def clear_screen
- end
-
- def set_screen_size(rows, columns)
- @screen_size = [rows, columns]
- end
-
- def set_winch_handler(&handler)
- end
-
- def in_pasting?
- @pasting
- end
-
- def prep
- end
-
- def deprep(otio)
- end
-end
diff --git a/lib/reline/io/windows.rb b/lib/reline/io/windows.rb
deleted file mode 100644
index 40025db504..0000000000
--- a/lib/reline/io/windows.rb
+++ /dev/null
@@ -1,513 +0,0 @@
-require 'fiddle/import'
-
-class Reline::Windows < Reline::IO
- def initialize
- @input_buf = []
- @output_buf = []
-
- @output = STDOUT
- @hsg = nil
- @getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
- @kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
- @GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
- @GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
- @SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
- @GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
- @FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
- @ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
- @hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
- @hConsoleInputHandle = @GetStdHandle.call(STD_INPUT_HANDLE)
- @GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
- @ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
- @GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
- @GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
- @FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
- @SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
-
- @GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
- @SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
- @WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
-
- @legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
- end
-
- def encoding
- Encoding::UTF_8
- end
-
- def win?
- true
- end
-
- def win_legacy_console?
- @legacy_console
- end
-
- def set_default_key_bindings(config)
- {
- [224, 72] => :ed_prev_history, # ↑
- [224, 80] => :ed_next_history, # ↓
- [224, 77] => :ed_next_char, # →
- [224, 75] => :ed_prev_char, # ←
- [224, 83] => :key_delete, # Del
- [224, 71] => :ed_move_to_beg, # Home
- [224, 79] => :ed_move_to_end, # End
- [ 0, 41] => :ed_unassigned, # input method on/off
- [ 0, 72] => :ed_prev_history, # ↑
- [ 0, 80] => :ed_next_history, # ↓
- [ 0, 77] => :ed_next_char, # →
- [ 0, 75] => :ed_prev_char, # ←
- [ 0, 83] => :key_delete, # Del
- [ 0, 71] => :ed_move_to_beg, # Home
- [ 0, 79] => :ed_move_to_end # End
- }.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, 32] => :em_set_mark, # M-<space>
- [24, 24] => :em_exchange_mark, # C-x C-x
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- end
-
- # Emulate ANSI key sequence.
- {
- [27, 91, 90] => :completion_journey_up, # S-Tab
- }.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)
- end
- end
-
- if defined? JRUBY_VERSION
- require 'win32api'
- else
- class Win32API
- DLL = {}
- TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
- POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
-
- WIN32_TYPES = "VPpNnLlIi"
- DL_TYPES = "0SSI"
-
- def initialize(dllname, func, import, export = "0", calltype = :stdcall)
- @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
- import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
- export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
- calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
-
- handle = DLL[dllname] ||=
- begin
- Fiddle.dlopen(dllname)
- rescue Fiddle::DLError
- raise unless File.extname(dllname).empty?
- Fiddle.dlopen(dllname + ".dll")
- end
-
- @func = Fiddle::Function.new(handle[func], import, export, calltype)
- rescue Fiddle::DLError => e
- raise LoadError, e.message, e.backtrace
- end
-
- def call(*args)
- import = @proto.split("")
- args.each_with_index do |x, i|
- args[i], = [x == 0 ? nil : +x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
- args[i], = [x].pack("I").unpack("i") if import[i] == "I"
- end
- ret, = @func.call(*args)
- return ret || 0
- end
- end
- end
-
- VK_RETURN = 0x0D
- VK_MENU = 0x12 # ALT key
- VK_LMENU = 0xA4
- VK_CONTROL = 0x11
- VK_SHIFT = 0x10
- VK_DIVIDE = 0x6F
-
- KEY_EVENT = 0x01
- WINDOW_BUFFER_SIZE_EVENT = 0x04
-
- CAPSLOCK_ON = 0x0080
- ENHANCED_KEY = 0x0100
- LEFT_ALT_PRESSED = 0x0002
- LEFT_CTRL_PRESSED = 0x0008
- NUMLOCK_ON = 0x0020
- RIGHT_ALT_PRESSED = 0x0001
- RIGHT_CTRL_PRESSED = 0x0004
- SCROLLLOCK_ON = 0x0040
- SHIFT_PRESSED = 0x0010
-
- VK_TAB = 0x09
- VK_END = 0x23
- VK_HOME = 0x24
- VK_LEFT = 0x25
- VK_UP = 0x26
- VK_RIGHT = 0x27
- VK_DOWN = 0x28
- VK_DELETE = 0x2E
-
- STD_INPUT_HANDLE = -10
- STD_OUTPUT_HANDLE = -11
- FILE_TYPE_PIPE = 0x0003
- FILE_NAME_INFO = 2
- ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
-
- # Calling Win32API with console handle is reported to fail after executing some external command.
- # We need to refresh console handle and retry the call again.
- private def call_with_console_handle(win32func, *args)
- val = win32func.call(@hConsoleHandle, *args)
- return val if val != 0
-
- @hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
- win32func.call(@hConsoleHandle, *args)
- end
-
- private def getconsolemode
- mode = "\000\000\000\000"
- call_with_console_handle(@GetConsoleMode, mode)
- mode.unpack1('L')
- end
-
- private def setconsolemode(mode)
- call_with_console_handle(@SetConsoleMode, mode)
- end
-
- #if @legacy_console
- # setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
- # @legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
- #end
-
- def msys_tty?(io = @hConsoleInputHandle)
- # check if fd is a pipe
- if @GetFileType.call(io) != FILE_TYPE_PIPE
- return false
- end
-
- bufsize = 1024
- p_buffer = "\0" * bufsize
- res = @GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
- return false if res == 0
-
- # get pipe name: p_buffer layout is:
- # struct _FILE_NAME_INFO {
- # DWORD FileNameLength;
- # WCHAR FileName[1];
- # } FILE_NAME_INFO
- len = p_buffer[0, 4].unpack1("L")
- name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
-
- # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
- # or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX')
- name =~ /(msys-|cygwin-).*-pty/ ? true : false
- end
-
- KEY_MAP = [
- # It's treated as Meta+Enter on Windows.
- [ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
- [ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
-
- # It's treated as Meta+Space on Windows.
- [ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
-
- # Emulate getwch() key sequences.
- [ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
- [ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
- [ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
- [ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
- [ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
- [ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
- [ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
-
- # Emulate ANSI key sequence.
- [ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
- ]
-
- def process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
-
- # high-surrogate
- if 0xD800 <= char_code and char_code <= 0xDBFF
- @hsg = char_code
- return
- end
- # low-surrogate
- if 0xDC00 <= char_code and char_code <= 0xDFFF
- if @hsg
- char_code = 0x10000 + (@hsg - 0xD800) * 0x400 + char_code - 0xDC00
- @hsg = nil
- else
- # no high-surrogate. ignored.
- return
- end
- else
- # ignore high-surrogate without low-surrogate if there
- @hsg = nil
- end
-
- key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
-
- match = KEY_MAP.find { |args,| key.matches?(**args) }
- unless match.nil?
- @output_buf.concat(match.last)
- return
- end
-
- # no char, only control keys
- return if key.char_code == 0 and key.control_keys.any?
-
- @output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
-
- @output_buf.concat(key.char.bytes)
- end
-
- def check_input_event
- num_of_events = 0.chr * 8
- while @output_buf.empty?
- Reline.core.line_editor.handle_signal
- if @WaitForSingleObject.(@hConsoleInputHandle, 100) != 0 # max 0.1 sec
- # prevent for background consolemode change
- @legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
- next
- end
- next if @GetNumberOfConsoleInputEvents.(@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
- input_records = 0.chr * 20 * 80
- read_event = 0.chr * 4
- if @ReadConsoleInputW.(@hConsoleInputHandle, input_records, 80, read_event) != 0
- read_events = read_event.unpack1('L')
- 0.upto(read_events) do |idx|
- input_record = input_records[idx * 20, 20]
- event = input_record[0, 2].unpack1('s*')
- case event
- when WINDOW_BUFFER_SIZE_EVENT
- @winch_handler.()
- when KEY_EVENT
- key_down = input_record[4, 4].unpack1('l*')
- repeat_count = input_record[8, 2].unpack1('s*')
- virtual_key_code = input_record[10, 2].unpack1('s*')
- virtual_scan_code = input_record[12, 2].unpack1('s*')
- char_code = input_record[14, 2].unpack1('S*')
- control_key_state = input_record[16, 2].unpack1('S*')
- is_key_down = key_down.zero? ? false : true
- if is_key_down
- process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
- end
- end
- end
- end
- end
- end
-
- def with_raw_input
- yield
- end
-
- def getc(_timeout_second)
- check_input_event
- @output_buf.shift
- end
-
- def ungetc(c)
- @output_buf.unshift(c)
- end
-
- def in_pasting?
- not empty_buffer?
- end
-
- def empty_buffer?
- if not @output_buf.empty?
- false
- elsif @kbhit.call == 0
- true
- else
- false
- end
- end
-
- def get_console_screen_buffer_info
- # CONSOLE_SCREEN_BUFFER_INFO
- # [ 0,2] dwSize.X
- # [ 2,2] dwSize.Y
- # [ 4,2] dwCursorPositions.X
- # [ 6,2] dwCursorPositions.Y
- # [ 8,2] wAttributes
- # [10,2] srWindow.Left
- # [12,2] srWindow.Top
- # [14,2] srWindow.Right
- # [16,2] srWindow.Bottom
- # [18,2] dwMaximumWindowSize.X
- # [20,2] dwMaximumWindowSize.Y
- csbi = 0.chr * 22
- return if call_with_console_handle(@GetConsoleScreenBufferInfo, csbi) == 0
- csbi
- end
-
- def get_screen_size
- unless csbi = get_console_screen_buffer_info
- return [1, 1]
- end
- csbi[0, 4].unpack('SS').reverse
- end
-
- def cursor_pos
- unless csbi = get_console_screen_buffer_info
- return Reline::CursorPos.new(0, 0)
- end
- x = csbi[4, 2].unpack1('s')
- y = csbi[6, 2].unpack1('s')
- Reline::CursorPos.new(x, y)
- end
-
- def move_cursor_column(val)
- call_with_console_handle(@SetConsoleCursorPosition, cursor_pos.y * 65536 + val)
- end
-
- def move_cursor_up(val)
- if val > 0
- y = cursor_pos.y - val
- y = 0 if y < 0
- call_with_console_handle(@SetConsoleCursorPosition, y * 65536 + cursor_pos.x)
- elsif val < 0
- move_cursor_down(-val)
- end
- end
-
- def move_cursor_down(val)
- if val > 0
- return unless csbi = get_console_screen_buffer_info
- screen_height = get_screen_size.first
- y = cursor_pos.y + val
- y = screen_height - 1 if y > (screen_height - 1)
- call_with_console_handle(@SetConsoleCursorPosition, (cursor_pos.y + val) * 65536 + cursor_pos.x)
- elsif val < 0
- move_cursor_up(-val)
- end
- end
-
- def erase_after_cursor
- return unless csbi = get_console_screen_buffer_info
- attributes = csbi[8, 2].unpack1('S')
- cursor = csbi[4, 4].unpack1('L')
- written = 0.chr * 4
- call_with_console_handle(@FillConsoleOutputCharacter, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
- call_with_console_handle(@FillConsoleOutputAttribute, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
- end
-
- def scroll_down(val)
- return if val < 0
- return unless csbi = get_console_screen_buffer_info
- buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
- screen_height = window_bottom - window_top + 1
- val = screen_height if val > screen_height
-
- if @legacy_console || window_left != 0
- # unless ENABLE_VIRTUAL_TERMINAL,
- # if srWindow.Left != 0 then it's conhost.exe hosted console
- # and puts "\n" causes horizontal scroll. its glitch.
- # FYI irb write from culumn 1, so this gives no gain.
- scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4')
- destination_origin = 0 # y * 65536 + x
- fill = [' '.ord, attributes].pack('SS')
- call_with_console_handle(@ScrollConsoleScreenBuffer, scroll_rectangle, nil, destination_origin, fill)
- else
- origin_x = x + 1
- origin_y = y - window_top + 1
- @output.write [
- (origin_y != screen_height) ? "\e[#{screen_height};H" : nil,
- "\n" * val,
- (origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil
- ].join
- end
- end
-
- def clear_screen
- if @legacy_console
- return unless csbi = get_console_screen_buffer_info
- buffer_width, _buffer_lines, attributes, window_top, window_bottom = csbi.unpack('ss@8S@12sx2s')
- fill_length = buffer_width * (window_bottom - window_top + 1)
- screen_topleft = window_top * 65536
- written = 0.chr * 4
- call_with_console_handle(@FillConsoleOutputCharacter, 0x20, fill_length, screen_topleft, written)
- call_with_console_handle(@FillConsoleOutputAttribute, attributes, fill_length, screen_topleft, written)
- call_with_console_handle(@SetConsoleCursorPosition, screen_topleft)
- else
- @output.write "\e[2J" "\e[H"
- end
- end
-
- def set_screen_size(rows, columns)
- raise NotImplementedError
- end
-
- def hide_cursor
- size = 100
- visible = 0 # 0 means false
- cursor_info = [size, visible].pack('Li')
- call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
- end
-
- def show_cursor
- size = 100
- visible = 1 # 1 means true
- cursor_info = [size, visible].pack('Li')
- call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
- end
-
- def set_winch_handler(&handler)
- @winch_handler = handler
- end
-
- def prep
- # do nothing
- nil
- end
-
- def deprep(otio)
- # do nothing
- end
-
- class KeyEventRecord
-
- attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
-
- def initialize(virtual_key_code, char_code, control_key_state)
- @virtual_key_code = virtual_key_code
- @char_code = char_code
- @control_key_state = control_key_state
- @enhanced = control_key_state & ENHANCED_KEY != 0
-
- (@control_keys = []).tap do |control_keys|
- # symbols must be sorted to make comparison is easier later on
- control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
- control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
- control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
- end.freeze
- end
-
- def char
- @char_code.chr(Encoding::UTF_8)
- end
-
- def enhanced?
- @enhanced
- end
-
- # Verifies if the arguments match with this key event.
- # Nil arguments are ignored, but at least one must be passed as non-nil.
- # To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
- def matches?(control_keys: nil, virtual_key_code: nil, char_code: nil)
- raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
-
- (control_keys.nil? || [*control_keys].sort == @control_keys) &&
- (virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
- (char_code.nil? || char_code == @char_code)
- end
-
- end
-end
diff --git a/lib/reline/key_actor.rb b/lib/reline/key_actor.rb
index 0ac7604556..ebe09d2009 100644
--- a/lib/reline/key_actor.rb
+++ b/lib/reline/key_actor.rb
@@ -2,7 +2,6 @@ module Reline::KeyActor
end
require 'reline/key_actor/base'
-require 'reline/key_actor/composite'
require 'reline/key_actor/emacs'
require 'reline/key_actor/vi_command'
require 'reline/key_actor/vi_insert'
diff --git a/lib/reline/key_actor/base.rb b/lib/reline/key_actor/base.rb
index ee28c7681e..a1cd7fb2a1 100644
--- a/lib/reline/key_actor/base.rb
+++ b/lib/reline/key_actor/base.rb
@@ -1,31 +1,19 @@
class Reline::KeyActor::Base
- def initialize(mapping = [])
- @mapping = mapping
- @matching_bytes = {}
- @key_bindings = {}
- end
+ MAPPING = Array.new(256)
def get_method(key)
- @mapping[key]
- end
-
- def add(key, func)
- (1...key.size).each do |size|
- @matching_bytes[key.take(size)] = true
- end
- @key_bindings[key] = func
+ self.class::MAPPING[key]
end
- def matching?(key)
- @matching_bytes[key]
+ def initialize
+ @default_key_bindings = {}
end
- def get(key)
- @key_bindings[key]
+ def default_key_bindings
+ @default_key_bindings
end
- def clear
- @matching_bytes.clear
- @key_bindings.clear
+ def reset_default_key_bindings
+ @default_key_bindings.clear
end
end
diff --git a/lib/reline/key_actor/composite.rb b/lib/reline/key_actor/composite.rb
deleted file mode 100644
index 37e94ce6cf..0000000000
--- a/lib/reline/key_actor/composite.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class Reline::KeyActor::Composite
- def initialize(key_actors)
- @key_actors = key_actors
- end
-
- def matching?(key)
- @key_actors.any? { |key_actor| key_actor.matching?(key) }
- end
-
- def get(key)
- @key_actors.each do |key_actor|
- func = key_actor.get(key)
- return func if func
- end
- nil
- end
-end
diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb
index ad84ee1d99..a561feee57 100644
--- a/lib/reline/key_actor/emacs.rb
+++ b/lib/reline/key_actor/emacs.rb
@@ -1,5 +1,5 @@
-module Reline::KeyActor
- EMACS_MAPPING = [
+class Reline::KeyActor::Emacs < Reline::KeyActor::Base
+ MAPPING = [
# 0 ^@
:em_set_mark,
# 1 ^A
@@ -19,7 +19,7 @@ module Reline::KeyActor
# 8 ^H
:em_delete_prev_char,
# 9 ^I
- :complete,
+ :ed_unassigned,
# 10 ^J
:ed_newline,
# 11 ^K
@@ -49,13 +49,13 @@ module Reline::KeyActor
# 23 ^W
:em_kill_region,
# 24 ^X
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 25 ^Y
:em_yank,
# 26 ^Z
:ed_ignore,
# 27 ^[
- :ed_unassigned,
+ :em_meta_next,
# 28 ^\
:ed_ignore,
# 29 ^]
@@ -63,7 +63,7 @@ module Reline::KeyActor
# 30 ^^
:ed_unassigned,
# 31 ^_
- :undo,
+ :ed_unassigned,
# 32 SPACE
:ed_insert,
# 33 !
@@ -319,9 +319,9 @@ module Reline::KeyActor
# 158 M-^^
:ed_unassigned,
# 159 M-^_
- :redo,
+ :em_copy_prev_word,
# 160 M-SPACE
- :em_set_mark,
+ :ed_unassigned,
# 161 M-!
:ed_unassigned,
# 162 M-"
@@ -415,7 +415,7 @@ module Reline::KeyActor
# 206 M-N
:vi_search_next,
# 207 M-O
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 208 M-P
:vi_search_prev,
# 209 M-Q
@@ -431,15 +431,15 @@ module Reline::KeyActor
# 214 M-V
:ed_unassigned,
# 215 M-W
- :ed_unassigned,
+ :em_copy_region,
# 216 M-X
- :ed_unassigned,
+ :ed_command,
# 217 M-Y
- :em_yank_pop,
+ :ed_unassigned,
# 218 M-Z
:ed_unassigned,
# 219 M-[
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 220 M-\
:ed_unassigned,
# 221 M-]
@@ -495,9 +495,9 @@ module Reline::KeyActor
# 246 M-v
:ed_unassigned,
# 247 M-w
- :ed_unassigned,
+ :em_copy_region,
# 248 M-x
- :ed_unassigned,
+ :ed_command,
# 249 M-y
:ed_unassigned,
# 250 M-z
diff --git a/lib/reline/key_actor/vi_command.rb b/lib/reline/key_actor/vi_command.rb
index d972c5e67f..98146d2f77 100644
--- a/lib/reline/key_actor/vi_command.rb
+++ b/lib/reline/key_actor/vi_command.rb
@@ -1,5 +1,5 @@
-module Reline::KeyActor
- VI_COMMAND_MAPPING = [
+class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
+ MAPPING = [
# 0 ^@
:ed_unassigned,
# 1 ^A
@@ -17,7 +17,7 @@ module Reline::KeyActor
# 7 ^G
:ed_unassigned,
# 8 ^H
- :ed_prev_char,
+ :ed_unassigned,
# 9 ^I
:ed_unassigned,
# 10 ^J
@@ -41,7 +41,7 @@ module Reline::KeyActor
# 19 ^S
:ed_ignore,
# 20 ^T
- :ed_transpose_chars,
+ :ed_unassigned,
# 21 ^U
:vi_kill_line_prev,
# 22 ^V
@@ -51,7 +51,7 @@ module Reline::KeyActor
# 24 ^X
:ed_unassigned,
# 25 ^Y
- :em_yank,
+ :ed_unassigned,
# 26 ^Z
:ed_unassigned,
# 27 ^[
@@ -75,7 +75,7 @@ module Reline::KeyActor
# 36 $
:ed_move_to_end,
# 37 %
- :ed_unassigned,
+ :vi_match,
# 38 &
:ed_unassigned,
# 39 '
@@ -89,11 +89,11 @@ module Reline::KeyActor
# 43 +
:ed_next_history,
# 44 ,
- :ed_unassigned,
+ :vi_repeat_prev_char,
# 45 -
:ed_prev_history,
# 46 .
- :ed_unassigned,
+ :vi_redo,
# 47 /
:vi_search_prev,
# 48 0
@@ -117,9 +117,9 @@ module Reline::KeyActor
# 57 9
:ed_argument_digit,
# 58 :
- :ed_unassigned,
+ :ed_command,
# 59 ;
- :ed_unassigned,
+ :vi_repeat_next_char,
# 60 <
:ed_unassigned,
# 61 =
@@ -157,21 +157,21 @@ module Reline::KeyActor
# 77 M
:ed_unassigned,
# 78 N
- :ed_unassigned,
+ :vi_repeat_search_prev,
# 79 O
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 80 P
:vi_paste_prev,
# 81 Q
:ed_unassigned,
# 82 R
- :ed_unassigned,
+ :vi_replace_mode,
# 83 S
- :ed_unassigned,
+ :vi_substitute_line,
# 84 T
:vi_to_prev_char,
# 85 U
- :ed_unassigned,
+ :vi_undo_line,
# 86 V
:ed_unassigned,
# 87 W
@@ -179,11 +179,11 @@ module Reline::KeyActor
# 88 X
:ed_delete_prev_char,
# 89 Y
- :ed_unassigned,
+ :vi_yank_end,
# 90 Z
:ed_unassigned,
# 91 [
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 92 \
:ed_unassigned,
# 93 ]
@@ -191,7 +191,7 @@ module Reline::KeyActor
# 94 ^
:vi_first_print,
# 95 _
- :ed_unassigned,
+ :vi_history_word,
# 96 `
:ed_unassigned,
# 97 a
@@ -221,7 +221,7 @@ module Reline::KeyActor
# 109 m
:ed_unassigned,
# 110 n
- :ed_unassigned,
+ :vi_repeat_search_next,
# 111 o
:ed_unassigned,
# 112 p
@@ -231,11 +231,11 @@ module Reline::KeyActor
# 114 r
:vi_replace_char,
# 115 s
- :ed_unassigned,
+ :vi_substitute_char,
# 116 t
:vi_to_next_char,
# 117 u
- :ed_unassigned,
+ :vi_undo,
# 118 v
:vi_histedit,
# 119 w
@@ -253,9 +253,9 @@ module Reline::KeyActor
# 125 }
:ed_unassigned,
# 126 ~
- :ed_unassigned,
+ :vi_change_case,
# 127 ^?
- :em_delete_prev_char,
+ :ed_unassigned,
# 128 M-^@
:ed_unassigned,
# 129 M-^A
@@ -415,7 +415,7 @@ module Reline::KeyActor
# 206 M-N
:ed_unassigned,
# 207 M-O
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 208 M-P
:ed_unassigned,
# 209 M-Q
@@ -439,7 +439,7 @@ module Reline::KeyActor
# 218 M-Z
:ed_unassigned,
# 219 M-[
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 220 M-\
:ed_unassigned,
# 221 M-]
diff --git a/lib/reline/key_actor/vi_insert.rb b/lib/reline/key_actor/vi_insert.rb
index 312df1646b..b8e89f81d8 100644
--- a/lib/reline/key_actor/vi_insert.rb
+++ b/lib/reline/key_actor/vi_insert.rb
@@ -1,5 +1,5 @@
-module Reline::KeyActor
- VI_INSERT_MAPPING = [
+class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
+ MAPPING = [
# 0 ^@
:ed_unassigned,
# 1 ^A
@@ -19,7 +19,7 @@ module Reline::KeyActor
# 8 ^H
:vi_delete_prev_char,
# 9 ^I
- :complete,
+ :ed_insert,
# 10 ^J
:ed_newline,
# 11 ^K
@@ -29,11 +29,11 @@ module Reline::KeyActor
# 13 ^M
:ed_newline,
# 14 ^N
- :menu_complete,
+ :ed_insert,
# 15 ^O
:ed_insert,
# 16 ^P
- :menu_complete_backward,
+ :ed_insert,
# 17 ^Q
:ed_ignore,
# 18 ^R
@@ -41,7 +41,7 @@ module Reline::KeyActor
# 19 ^S
:vi_search_next,
# 20 ^T
- :ed_transpose_chars,
+ :ed_insert,
# 21 ^U
:vi_kill_line_prev,
# 22 ^V
@@ -51,7 +51,7 @@ module Reline::KeyActor
# 24 ^X
:ed_insert,
# 25 ^Y
- :em_yank,
+ :ed_insert,
# 26 ^Z
:ed_insert,
# 27 ^[
diff --git a/lib/reline/key_stroke.rb b/lib/reline/key_stroke.rb
index ba40899685..c1c61513a9 100644
--- a/lib/reline/key_stroke.rb
+++ b/lib/reline/key_stroke.rb
@@ -1,108 +1,104 @@
class Reline::KeyStroke
- ESC_BYTE = 27
- CSI_PARAMETER_BYTES_RANGE = 0x30..0x3f
- CSI_INTERMEDIATE_BYTES_RANGE = (0x20..0x2f)
-
def initialize(config)
@config = config
end
- # Input exactly matches to a key sequence
- MATCHING = :matching
- # Input partially matches to a key sequence
- MATCHED = :matched
- # Input matches to a key sequence and the key sequence is a prefix of another key sequence
- MATCHING_MATCHED = :matching_matched
- # Input does not match to any key sequence
- UNMATCHED = :unmatched
-
- def match_status(input)
- matching = key_mapping.matching?(input)
- matched = key_mapping.get(input)
-
- # FIXME: Workaround for single byte. remove this after MAPPING is merged into KeyActor.
- matched ||= input.size == 1
- matching ||= input == [ESC_BYTE]
-
- if matching && matched
- MATCHING_MATCHED
- elsif matching
- MATCHING
- elsif matched
- MATCHED
- elsif input[0] == ESC_BYTE
- match_unknown_escape_sequence(input, vi_mode: @config.editing_mode_is?(:vi_insert, :vi_command))
- elsif input.size == 1
- MATCHED
- else
- UNMATCHED
- end
+ def compress_meta_key(ary)
+ return ary unless @config.convert_meta
+ ary.inject([]) { |result, key|
+ if result.size > 0 and result.last == "\e".ord
+ result[result.size - 1] = Reline::Key.new(key, key | 0b10000000, true)
+ else
+ result << key
+ end
+ result
+ }
end
- def expand(input)
- matched_bytes = nil
- (1..input.size).each do |i|
- bytes = input.take(i)
- status = match_status(bytes)
- matched_bytes = bytes if status == MATCHED || status == MATCHING_MATCHED
+ def start_with?(me, other)
+ compressed_me = compress_meta_key(me)
+ compressed_other = compress_meta_key(other)
+ i = 0
+ loop do
+ my_c = compressed_me[i]
+ other_c = compressed_other[i]
+ other_is_last = (i + 1) == compressed_other.size
+ me_is_last = (i + 1) == compressed_me.size
+ if my_c != other_c
+ if other_c == "\e".ord and other_is_last and my_c.is_a?(Reline::Key) and my_c.with_meta
+ return true
+ else
+ return false
+ end
+ elsif other_is_last
+ return true
+ elsif me_is_last
+ return false
+ end
+ i += 1
end
- return [[], []] unless matched_bytes
+ end
- func = key_mapping.get(matched_bytes)
- if func.is_a?(Array)
- keys = func.map { |c| Reline::Key.new(c, c, false) }
- elsif func
- keys = [Reline::Key.new(func, func, false)]
- elsif matched_bytes.size == 1
- keys = [Reline::Key.new(matched_bytes.first, matched_bytes.first, false)]
- elsif matched_bytes.size == 2 && matched_bytes[0] == ESC_BYTE
- keys = [Reline::Key.new(matched_bytes[1], matched_bytes[1] | 0b10000000, true)]
- else
- keys = []
+ def equal?(me, other)
+ case me
+ when Array
+ compressed_me = compress_meta_key(me)
+ compressed_other = compress_meta_key(other)
+ compressed_me.size == compressed_other.size and [compressed_me, compressed_other].transpose.all?{ |i| equal?(i[0], i[1]) }
+ when Integer
+ if other.is_a?(Reline::Key)
+ if other.combined_char == "\e".ord
+ false
+ else
+ other.combined_char == me
+ end
+ else
+ me == other
+ end
+ when Reline::Key
+ if other.is_a?(Integer)
+ me.combined_char == other
+ else
+ me == other
+ end
end
-
- [keys, input.drop(matched_bytes.size)]
end
- private
-
- # returns match status of CSI/SS3 sequence and matched length
- def match_unknown_escape_sequence(input, vi_mode: false)
- idx = 0
- return UNMATCHED unless input[idx] == ESC_BYTE
- idx += 1
- idx += 1 if input[idx] == ESC_BYTE
+ def match_status(input)
+ key_mapping.keys.select { |lhs|
+ start_with?(lhs, input)
+ }.tap { |it|
+ return :matched if it.size == 1 && equal?(it[0], input)
+ return :matching if it.size == 1 && !equal?(it[0], input)
+ return :matched if it.max_by(&:size)&.size&.< input.size
+ return :matching if it.size > 1
+ }
+ key_mapping.keys.select { |lhs|
+ start_with?(input, lhs)
+ }.tap { |it|
+ return it.size > 0 ? :matched : :unmatched
+ }
+ end
- case input[idx]
- when nil
- if idx == 1 # `ESC`
- return MATCHING_MATCHED
- else # `ESC ESC`
- return MATCHING
- end
- when 91 # == '['.ord
- # CSI sequence `ESC [ ... char`
- 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])
- when 79 # == 'O'.ord
- # SS3 sequence `ESC O char`
- idx += 1
- else
- # `ESC char` or `ESC ESC char`
- return UNMATCHED if vi_mode
- end
+ def expand(input)
+ input = compress_meta_key(input)
+ lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last
+ return input unless lhs
+ rhs = key_mapping[lhs]
- case input.size
- when idx
- MATCHING
- when idx + 1
- MATCHED
- else
- UNMATCHED
+ case rhs
+ when String
+ rhs_bytes = rhs.bytes
+ expand(expand(rhs_bytes) + expand(input.drop(lhs.size)))
+ when Symbol
+ [rhs] + expand(input.drop(lhs.size))
+ when Array
+ rhs
end
end
+ private
+
def key_mapping
@config.key_bindings
end
diff --git a/lib/reline/kill_ring.rb b/lib/reline/kill_ring.rb
index 201f6f3ca0..bb3684b42b 100644
--- a/lib/reline/kill_ring.rb
+++ b/lib/reline/kill_ring.rb
@@ -14,7 +14,7 @@ class Reline::KillRing
end
def ==(other)
- equal?(other)
+ object_id == other.object_id
end
end
@@ -68,7 +68,7 @@ class Reline::KillRing
def append(string, before_p = false)
case @state
when State::FRESH, State::YANK
- @ring << RingPoint.new(+string)
+ @ring << RingPoint.new(string)
@state = State::CONTINUED
when State::CONTINUED, State::PROCESSED
if before_p
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index c71a5f79ee..8153aaba05 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -4,7 +4,9 @@ require 'reline/unicode'
require 'tempfile'
class Reline::LineEditor
+ # TODO: undo
# TODO: Use "private alias_method" idiom after drop Ruby 2.5.
+ attr_reader :line
attr_reader :byte_pointer
attr_accessor :confirm_multiline_termination_proc
attr_accessor :completion_proc
@@ -12,6 +14,7 @@ class Reline::LineEditor
attr_accessor :output_modifier_proc
attr_accessor :prompt_proc
attr_accessor :auto_indent_proc
+ attr_accessor :pre_input_hook
attr_accessor :dig_perfect_match_proc
attr_writer :output
@@ -32,94 +35,98 @@ class Reline::LineEditor
vi_next_big_word
vi_prev_big_word
vi_end_big_word
+ vi_repeat_next_char
+ vi_repeat_prev_char
}
module CompletionState
NORMAL = :normal
COMPLETION = :completion
MENU = :menu
+ JOURNEY = :journey
MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
PERFECT_MATCH = :perfect_match
end
- RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true)
+ CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
+ MenuInfo = Struct.new('MenuInfo', :target, :list)
- CompletionJourneyState = Struct.new(:line_index, :pre, :target, :post, :list, :pointer)
- NullActionState = [nil, nil].freeze
-
- class MenuInfo
- attr_reader :list
-
- def initialize(list)
- @list = list
- end
-
- def lines(screen_width)
- return [] if @list.empty?
-
- list = @list.sort
- sizes = list.map { |item| Reline::Unicode.calculate_width(item) }
- item_width = sizes.max + 2
- num_cols = [screen_width / item_width, 1].max
- num_rows = list.size.fdiv(num_cols).ceil
- list_with_padding = list.zip(sizes).map { |item, size| item + ' ' * (item_width - size) }
- aligned = (list_with_padding + [nil] * (num_rows * num_cols - list_with_padding.size)).each_slice(num_rows).to_a.transpose
- aligned.map do |row|
- row.join.rstrip
- end
- end
- end
-
- MINIMUM_SCROLLBAR_HEIGHT = 1
+ PROMPT_LIST_CACHE_TIMEOUT = 0.5
def initialize(config, encoding)
@config = config
@completion_append_character = ''
- @screen_size = [0, 0] # Should be initialized with actual winsize in LineEditor#reset
reset_variables(encoding: encoding)
end
- def io_gate
- Reline::IOGate
- end
-
def set_pasting_state(in_pasting)
- # While pasting, text to be inserted is stored to @continuous_insertion_buffer.
- # After pasting, this buffer should be force inserted.
- process_insert(force: true) if @in_pasting && !in_pasting
@in_pasting = in_pasting
end
+ def simplified_rendering?
+ if finished?
+ false
+ elsif @just_cursor_moving and not @rerender_all
+ true
+ else
+ not @rerender_all and not finished? and @in_pasting
+ end
+ end
+
private def check_mode_string
+ mode_string = nil
if @config.show_mode_in_prompt
if @config.editing_mode_is?(:vi_command)
- @config.vi_cmd_mode_string
+ mode_string = @config.vi_cmd_mode_string
elsif @config.editing_mode_is?(:vi_insert)
- @config.vi_ins_mode_string
+ mode_string = @config.vi_ins_mode_string
elsif @config.editing_mode_is?(:emacs)
- @config.emacs_mode_string
+ mode_string = @config.emacs_mode_string
else
- '?'
+ mode_string = '?'
end
end
+ if mode_string != @prev_mode_string
+ @rerender_all = true
+ end
+ @prev_mode_string = mode_string
+ mode_string
end
- private def check_multiline_prompt(buffer, mode_string)
+ private def check_multiline_prompt(buffer)
if @vi_arg
prompt = "(arg: #{@vi_arg}) "
+ @rerender_all = true
elsif @searching_prompt
prompt = @searching_prompt
+ @rerender_all = true
else
prompt = @prompt
end
- if !@is_multiline
+ if simplified_rendering?
mode_string = check_mode_string
prompt = mode_string + prompt if mode_string
- [prompt] + [''] * (buffer.size - 1)
- elsif @prompt_proc
- prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
+ return [prompt, calculate_width(prompt, true), [prompt] * buffer.size]
+ end
+ if @prompt_proc
+ use_cached_prompt_list = false
+ if @cached_prompt_list
+ if @just_cursor_moving
+ use_cached_prompt_list = true
+ elsif Time.now.to_f < (@prompt_cache_time + PROMPT_LIST_CACHE_TIMEOUT) and buffer.size == @cached_prompt_list.size
+ use_cached_prompt_list = true
+ end
+ end
+ use_cached_prompt_list = false if @rerender_all
+ if use_cached_prompt_list
+ prompt_list = @cached_prompt_list
+ else
+ prompt_list = @cached_prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
+ @prompt_cache_time = Time.now.to_f
+ end
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
prompt_list = [prompt] if prompt_list.empty?
+ mode_string = check_mode_string
prompt_list = prompt_list.map{ |pr| mode_string + pr } if mode_string
prompt = prompt_list[@line_index]
prompt = prompt_list[0] if prompt.nil?
@@ -129,17 +136,24 @@ class Reline::LineEditor
prompt_list << prompt_list.last
end
end
- prompt_list
+ prompt_width = calculate_width(prompt, true)
+ [prompt, prompt_width, prompt_list]
else
+ mode_string = check_mode_string
prompt = mode_string + prompt if mode_string
- [prompt] * buffer.size
+ prompt_width = calculate_width(prompt, true)
+ [prompt, prompt_width, nil]
end
end
def reset(prompt = '', encoding:)
+ @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
@screen_size = Reline::IOGate.get_screen_size
+ @screen_height = @screen_size.first
reset_variables(prompt, encoding: encoding)
- @rendered_screen.base_y = Reline::IOGate.cursor_pos.y
+ Reline::IOGate.set_winch_handler do
+ @resized = true
+ end
if ENV.key?('RELINE_ALT_SCROLLBAR')
@full_block = '::'
@upper_half_block = "''"
@@ -163,56 +177,82 @@ class Reline::LineEditor
end
end
- def handle_signal
- handle_interrupted
- handle_resized
- end
-
- private def handle_resized
+ def resize
return unless @resized
-
- @screen_size = Reline::IOGate.get_screen_size
@resized = false
- scroll_into_view
- Reline::IOGate.move_cursor_up @rendered_screen.cursor_y
- @rendered_screen.base_y = Reline::IOGate.cursor_pos.y
- clear_rendered_screen_cache
- render
- end
-
- private def handle_interrupted
- return unless @interrupted
-
- @interrupted = false
- clear_dialogs
- render
- cursor_to_bottom_offset = @rendered_screen.lines.size - @rendered_screen.cursor_y
- Reline::IOGate.scroll_down cursor_to_bottom_offset
- Reline::IOGate.move_cursor_column 0
- clear_rendered_screen_cache
- case @old_trap
- when 'DEFAULT', 'SYSTEM_DEFAULT'
- raise Interrupt
- when 'IGNORE'
- # Do nothing
- when 'EXIT'
- exit
+ @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
+ old_screen_size = @screen_size
+ @screen_size = Reline::IOGate.get_screen_size
+ @screen_height = @screen_size.first
+ if old_screen_size.last < @screen_size.last # columns increase
+ @rerender_all = true
+ rerender
else
- @old_trap.call if @old_trap.respond_to?(:call)
+ back = 0
+ new_buffer = whole_lines
+ prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
+ new_buffer.each_with_index do |line, index|
+ prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
+ width = prompt_width + calculate_width(line)
+ height = calculate_height_by_width(width)
+ back += height
+ end
+ @highest_in_all = back
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
+ @first_line_started_from =
+ if @line_index.zero?
+ 0
+ else
+ calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
+ end
+ if @prompt_proc
+ prompt = prompt_list[@line_index]
+ prompt_width = calculate_width(prompt, true)
+ end
+ calculate_nearest_cursor
+ @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
+ @rerender_all = true
end
end
def set_signal_handlers
- Reline::IOGate.set_winch_handler do
- @resized = true
- end
- @old_trap = Signal.trap('INT') do
- @interrupted = true
+ @old_trap = Signal.trap('INT') {
+ clear_dialog
+ if @scroll_partial_screen
+ move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
+ else
+ move_cursor_down(@highest_in_all - @line_index - 1)
+ end
+ Reline::IOGate.move_cursor_column(0)
+ scroll_down(1)
+ case @old_trap
+ when 'DEFAULT', 'SYSTEM_DEFAULT'
+ raise Interrupt
+ when 'IGNORE'
+ # Do nothing
+ when 'EXIT'
+ exit
+ else
+ @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?
@@ -225,45 +265,55 @@ class Reline::LineEditor
@encoding = encoding
@is_multiline = false
@finished = false
+ @cleared = false
+ @rerender_all = false
@history_pointer = nil
@kill_ring ||= Reline::KillRing.new
@vi_clipboard = ''
@vi_arg = nil
@waiting_proc = nil
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- @completion_journey_state = nil
+ @waiting_operator_proc = nil
+ @waiting_operator_vi_arg = nil
+ @completion_journey_data = nil
@completion_state = CompletionState::NORMAL
@perfect_matched = nil
@menu_info = nil
+ @first_prompt = true
@searching_prompt = nil
- @just_cursor_moving = false
+ @first_char = true
+ @add_newline_to_end_of_buffer = false
+ @just_cursor_moving = nil
+ @cached_prompt_list = nil
+ @prompt_cache_time = nil
@eof = false
@continuous_insertion_buffer = String.new(encoding: @encoding)
- @scroll_partial_screen = 0
+ @scroll_partial_screen = nil
+ @prev_mode_string = nil
@drop_terminate_spaces = false
@in_pasting = false
@auto_indent_proc = nil
@dialogs = []
- @interrupted = false
+ @last_key = nil
@resized = false
- @cache = {}
- @rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
- @input_lines = [[[""], 0, 0]]
- @input_lines_position = 0
- @undoing = false
- @prev_action_state = NullActionState
- @next_action_state = NullActionState
reset_line
end
def reset_line
+ @cursor = 0
+ @cursor_max = 0
@byte_pointer = 0
@buffer_of_lines = [String.new(encoding: @encoding)]
@line_index = 0
- @cache.clear
+ @previous_line_index = nil
+ @line = @buffer_of_lines[0]
+ @first_line_started_from = 0
+ @move_up = 0
+ @started_from = 0
+ @highest_in_this = 1
+ @highest_in_all = 1
@line_backup_in_history = nil
@multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
+ @check_new_auto_indent = false
end
def multiline_on
@@ -274,44 +324,68 @@ class Reline::LineEditor
@is_multiline = false
end
+ private def calculate_height_by_lines(lines, prompt)
+ result = 0
+ prompt_list = prompt.is_a?(Array) ? prompt : nil
+ lines.each_with_index { |line, i|
+ prompt = prompt_list[i] if prompt_list and prompt_list[i]
+ result += calculate_height_by_width(calculate_width(prompt, true) + calculate_width(line))
+ }
+ result
+ end
+
private def insert_new_line(cursor_line, next_line)
+ @line = cursor_line
@buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: @encoding))
- @buffer_of_lines[@line_index] = cursor_line
+ @previous_line_index = @line_index
@line_index += 1
- @byte_pointer = 0
- if @auto_indent_proc && !@in_pasting
- if next_line.empty?
- (
- # For compatibility, use this calculation instead of just `process_auto_indent @line_index - 1, cursor_dependent: false`
- indent1 = @auto_indent_proc.(@buffer_of_lines.take(@line_index - 1).push(''), @line_index - 1, 0, true)
- indent2 = @auto_indent_proc.(@buffer_of_lines.take(@line_index), @line_index - 1, @buffer_of_lines[@line_index - 1].bytesize, false)
- indent = indent2 || indent1
- @buffer_of_lines[@line_index - 1] = ' ' * indent + @buffer_of_lines[@line_index - 1].gsub(/\A\s*/, '')
- )
- process_auto_indent @line_index, add_newline: true
- else
- process_auto_indent @line_index - 1, cursor_dependent: false
- process_auto_indent @line_index, add_newline: true # Need for compatibility
- process_auto_indent @line_index, cursor_dependent: false
- end
+ @just_cursor_moving = false
+ end
+
+ private def calculate_height_by_width(width)
+ width.div(@screen_size.last) + 1
+ end
+
+ private def split_by_width(str, max_width)
+ Reline::Unicode.split_by_width(str, max_width, @encoding)
+ end
+
+ private def scroll_down(val)
+ if val <= @rest_height
+ Reline::IOGate.move_cursor_down(val)
+ @rest_height -= val
+ else
+ Reline::IOGate.move_cursor_down(@rest_height)
+ Reline::IOGate.scroll_down(val - @rest_height)
+ @rest_height = 0
end
end
- private def split_by_width(str, max_width, offset: 0)
- Reline::Unicode.split_by_width(str, max_width, @encoding, offset: offset)
+ private def move_cursor_up(val)
+ if val > 0
+ Reline::IOGate.move_cursor_up(val)
+ @rest_height += val
+ elsif val < 0
+ move_cursor_down(-val)
+ end
end
- def current_byte_pointer_cursor
- calculate_width(current_line.byteslice(0, @byte_pointer))
+ private def move_cursor_down(val)
+ if val > 0
+ Reline::IOGate.move_cursor_down(val)
+ @rest_height -= val
+ @rest_height = 0 if @rest_height < 0
+ elsif val < 0
+ move_cursor_up(-val)
+ end
end
- private def calculate_nearest_cursor(cursor)
- line_to_calc = current_line
+ private def calculate_nearest_cursor(line_to_calc = @line, cursor = @cursor, started_from = @started_from, byte_pointer = @byte_pointer, update = true)
new_cursor_max = calculate_width(line_to_calc)
new_cursor = 0
new_byte_pointer = 0
height = 1
- max_width = screen_width
+ max_width = @screen_size.last
if @config.editing_mode_is?(:vi_command)
last_byte_size = Reline::Unicode.get_prev_mbchar_size(line_to_calc, line_to_calc.bytesize)
if last_byte_size > 0
@@ -337,227 +411,120 @@ class Reline::LineEditor
end
new_byte_pointer += gc.bytesize
end
- @byte_pointer = new_byte_pointer
- end
-
- def with_cache(key, *deps)
- cached_deps, value = @cache[key]
- if cached_deps != deps
- @cache[key] = [deps, value = yield(*deps, cached_deps, value)]
+ new_started_from = height - 1
+ if update
+ @cursor = new_cursor
+ @cursor_max = new_cursor_max
+ @started_from = new_started_from
+ @byte_pointer = new_byte_pointer
+ else
+ [new_cursor, new_cursor_max, new_started_from, new_byte_pointer]
end
- value
end
- def modified_lines
- with_cache(__method__, whole_lines, finished?) do |whole, complete|
- modify_lines(whole, complete)
- end
+ def rerender_all
+ @rerender_all = true
+ process_insert(force: true)
+ rerender
end
- def prompt_list
- with_cache(__method__, whole_lines, check_mode_string, @vi_arg, @searching_prompt) do |lines, mode_string|
- check_multiline_prompt(lines, mode_string)
+ def rerender
+ return if @line.nil?
+ if @menu_info
+ scroll_down(@highest_in_all - @first_line_started_from)
+ @rerender_all = true
end
- end
-
- def screen_height
- @screen_size.first
- end
-
- def screen_width
- @screen_size.last
- end
-
- def screen_scroll_top
- @scroll_partial_screen
- end
-
- def wrapped_prompt_and_input_lines
- with_cache(__method__, @buffer_of_lines.size, modified_lines, prompt_list, screen_width) do |n, lines, prompts, width, prev_cache_key, cached_value|
- prev_n, prev_lines, prev_prompts, prev_width = prev_cache_key
- cached_wraps = {}
- if prev_width == width
- prev_n.times do |i|
- cached_wraps[[prev_prompts[i], prev_lines[i]]] = cached_value[i]
- end
- end
-
- n.times.map do |i|
- prompt = prompts[i] || ''
- line = lines[i] || ''
- if (cached = cached_wraps[[prompt, line]])
- next cached
- end
- *wrapped_prompts, code_line_prompt = split_by_width(prompt, width).first.compact
- wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt, true)).first.compact
- wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
- end
+ if @menu_info
+ show_menu
+ @menu_info = nil
end
- end
-
- def calculate_overlay_levels(overlay_levels)
- levels = []
- overlay_levels.each do |x, w, l|
- levels.fill(l, x, w)
+ prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
+ if @cleared
+ clear_screen_buffer(prompt, prompt_list, prompt_width)
+ @cleared = false
+ return
end
- levels
- end
-
- def render_line_differential(old_items, new_items)
- old_levels = calculate_overlay_levels(old_items.zip(new_items).each_with_index.map {|((x, w, c), (nx, _nw, nc)), i| [x, w, c == nc && x == nx ? i : -1] if x }.compact)
- new_levels = calculate_overlay_levels(new_items.each_with_index.map { |(x, w), i| [x, w, i] if x }.compact).take(screen_width)
- base_x = 0
- new_levels.zip(old_levels).chunk { |n, o| n == o ? :skip : n || :blank }.each do |level, chunk|
- width = chunk.size
- if level == :skip
- # do nothing
- elsif level == :blank
- Reline::IOGate.move_cursor_column base_x
- @output.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
+ if @is_multiline and finished? and @scroll_partial_screen
+ # Re-output all code higher than the screen when finished.
+ Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
+ Reline::IOGate.move_cursor_column(0)
+ @scroll_partial_screen = nil
+ 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
- x, w, content = new_items[level]
- cover_begin = base_x != 0 && new_levels[base_x - 1] == level
- cover_end = new_levels[base_x + width] == level
- pos = 0
- unless x == base_x && w == width
- content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
- end
- Reline::IOGate.move_cursor_column x + pos
- @output.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
+ new_lines = whole_lines
end
- base_x += width
- end
- if old_levels.size > new_levels.size
- Reline::IOGate.move_cursor_column new_levels.size
- Reline::IOGate.erase_after_cursor
- end
- end
-
- # Calculate cursor position in word wrapped content.
- def wrapped_cursor_position
- prompt_width = calculate_width(prompt_list[@line_index], true)
- line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
- wrapped_line_before_cursor = split_by_width(' ' * prompt_width + line_before_cursor, screen_width).first.compact
- wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
- wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
- [wrapped_cursor_x, wrapped_cursor_y]
- end
-
- def clear_dialogs
- @dialogs.each do |dialog|
- dialog.contents = nil
- dialog.trap_key = nil
- end
- end
-
- def update_dialogs(key = nil)
- wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
- @dialogs.each do |dialog|
- dialog.trap_key = nil
- update_each_dialog(dialog, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top, key)
- end
- end
-
- def render_finished
- render_differential([], 0, 0)
- lines = @buffer_of_lines.size.times.map do |i|
- line = prompt_list[i] + modified_lines[i]
- wrapped_lines, = split_by_width(line, screen_width)
- wrapped_lines.last.empty? ? "#{line} " : line
- end
- @output.puts lines.map { |l| "#{l}\r\n" }.join
- end
-
- def print_nomultiline_prompt
- # Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence.
- @output.write @prompt if @prompt && !@is_multiline
- end
-
- def render
- wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
- new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
- prompt_width = Reline::Unicode.calculate_width(prompt, true)
- [[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
- end
- if @menu_info
- @menu_info.lines(screen_width).each do |item|
- new_lines << [[0, Reline::Unicode.calculate_width(item), item]]
+ modify_lines(new_lines).each_with_index do |line, index|
+ @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\n"
+ Reline::IOGate.erase_after_cursor
end
- @menu_info = nil # TODO: do not change state here
+ @output.flush
+ clear_dialog
+ return
end
-
- @dialogs.each_with_index do |dialog, index|
- next unless dialog.contents
-
- x_range, y_range = dialog_range dialog, wrapped_cursor_y - screen_scroll_top
- y_range.each do |row|
- next if row < 0 || row >= screen_height
-
- dialog_rows = new_lines[row] ||= []
- # index 0 is for prompt, index 1 is for line, index 2.. is for dialog
- dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
+ 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_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_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_content
+ rerender_changed_current_line
+ @previous_line_index = nil
+ rendered = true
+ elsif @rerender_all
+ rerender_all_lines
+ @rerender_all = false
+ rendered = true
+ else
end
end
-
- render_differential new_lines, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top
- end
-
- # Reflects lines to be rendered and new cursor position to the screen
- # by calculating the difference from the previous render.
-
- private def render_differential(new_lines, new_cursor_x, new_cursor_y)
- rendered_lines = @rendered_screen.lines
- cursor_y = @rendered_screen.cursor_y
- if new_lines != rendered_lines
- # Hide cursor while rendering to avoid cursor flickering.
- Reline::IOGate.hide_cursor
- num_lines = [[new_lines.size, rendered_lines.size].max, screen_height].min
- if @rendered_screen.base_y + num_lines > screen_height
- Reline::IOGate.scroll_down(num_lines - cursor_y - 1)
- @rendered_screen.base_y = screen_height - num_lines
- cursor_y = num_lines - 1
- end
- num_lines.times do |i|
- rendered_line = rendered_lines[i] || []
- line_to_render = new_lines[i] || []
- next if rendered_line == line_to_render
-
- Reline::IOGate.move_cursor_down i - cursor_y
- cursor_y = i
- unless rendered_lines[i]
- Reline::IOGate.move_cursor_column 0
- Reline::IOGate.erase_after_cursor
+ if @is_multiline
+ if finished?
+ # Always rerender on finish because output_modifier_proc may return a different output.
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
+ else
+ new_lines = whole_lines
end
- render_line_differential(rendered_line, line_to_render)
+ line = modify_lines(new_lines)[@line_index]
+ 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)
+ scroll_down(1)
+ Reline::IOGate.move_cursor_column(0)
+ Reline::IOGate.erase_after_cursor
+ else
+ if not rendered and not @in_pasting
+ line = modify_lines(whole_lines)[@line_index]
+ prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
+ render_partial(prompt, prompt_width, line, @first_line_started_from)
+ end
+ render_dialog((prompt_width + @cursor) % @screen_size.last)
+ end
+ @buffer_of_lines[@line_index] = @line
+ @rest_height = 0 if @scroll_partial_screen
+ else
+ line = modify_lines(whole_lines)[@line_index]
+ render_partial(prompt, prompt_width, line, 0)
+ if finished?
+ scroll_down(1)
+ Reline::IOGate.move_cursor_column(0)
+ Reline::IOGate.erase_after_cursor
end
- @rendered_screen.lines = new_lines
- Reline::IOGate.show_cursor
end
- Reline::IOGate.move_cursor_column new_cursor_x
- Reline::IOGate.move_cursor_down new_cursor_y - cursor_y
- @rendered_screen.cursor_y = new_cursor_y
- end
-
- private def clear_rendered_screen_cache
- @rendered_screen.lines = []
- @rendered_screen.cursor_y = 0
- end
-
- def upper_space_height(wrapped_cursor_y)
- wrapped_cursor_y - screen_scroll_top
- end
-
- def rest_height(wrapped_cursor_y)
- screen_height - wrapped_cursor_y + screen_scroll_top - @rendered_screen.base_y - 1
- end
-
- def rerender
- render unless @in_pasting
end
class DialogProcScope
- CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
-
def initialize(line_editor, config, proc_to_exec, context)
@line_editor = line_editor
@config = config
@@ -608,20 +575,11 @@ class Reline::LineEditor
end
def screen_width
- @line_editor.screen_width
- end
-
- def screen_height
- @line_editor.screen_height
- end
-
- def preferred_dialog_height
- _wrapped_cursor_x, wrapped_cursor_y = @line_editor.wrapped_cursor_position
- [@line_editor.upper_space_height(wrapped_cursor_y), @line_editor.rest_height(wrapped_cursor_y), (screen_height + 6) / 5].max
+ @line_editor.instance_variable_get(:@screen_size).last
end
def completion_journey_data
- @line_editor.dialog_proc_scope_completion_journey_data
+ @line_editor.instance_variable_get(:@completion_journey_data)
end
def config
@@ -635,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
@@ -670,8 +628,10 @@ class Reline::LineEditor
@trap_key.each do |t|
@config.add_oneshot_key_binding(t, @name)
end
- else
+ elsif @trap_key.is_a?(Array)
@config.add_oneshot_key_binding(@trap_key, @name)
+ elsif @trap_key.is_a?(Integer) or @trap_key.is_a?(Reline::Key)
+ @config.add_oneshot_key_binding([@trap_key], @name)
end
end
dialog_render_info
@@ -688,31 +648,52 @@ class Reline::LineEditor
end
DIALOG_DEFAULT_HEIGHT = 20
+ private def render_dialog(cursor_column)
+ @dialogs.each do |dialog|
+ render_each_dialog(dialog, cursor_column)
+ end
+ 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]
+ private def padding_space_with_escape_sequences(str, width)
+ padding_width = width - calculate_width(str, true)
+ # padding_width should be only positive value. But macOS and Alacritty returns negative value.
+ padding_width = 0 if padding_width < 0
+ str + (' ' * padding_width)
end
- private def update_each_dialog(dialog, cursor_column, cursor_row, key = nil)
- dialog.set_cursor_pos(cursor_column, cursor_row)
- dialog_render_info = dialog.call(key)
+ private def render_each_dialog(dialog, cursor_column)
+ if @in_pasting
+ clear_each_dialog(dialog)
+ dialog.contents = nil
+ dialog.trap_key = nil
+ return
+ end
+ 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
@@ -722,77 +703,591 @@ 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
- diff = (dialog.column + dialog.width) - screen_width
+ dialog.width += @block_elem_width if dialog.scrollbar_pos
+ diff = (dialog.column + dialog.width) - (@screen_size.last)
if diff > 0
dialog.column -= diff
end
- if rest_height(screen_scroll_top + cursor_row) - dialog_render_info.pos.y >= height
+ if (@rest_height - dialog_render_info.pos.y) >= height
dialog.vertical_offset = dialog_render_info.pos.y + 1
- elsif cursor_row >= height
+ 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_width
- 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)
- str, = Reline::Unicode.take_mbchar_range(item, 0, str_width, padding: true)
- 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
+ dialog.width = @screen_size.last
+ end
+ 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)
+ @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
+ @output.write ' ' * @block_elem_width
+ end
+ 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 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
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ end
+
+ 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
+ if cursor_y == 0
+ @scroll_partial_screen = 0
+ elsif cursor_y == (highest_in_all - 1)
+ @scroll_partial_screen = highest_in_all - @screen_height
+ else
+ if @scroll_partial_screen
+ if cursor_y <= @scroll_partial_screen
+ @scroll_partial_screen = cursor_y
+ elsif (@scroll_partial_screen + @screen_height - 1) < cursor_y
+ @scroll_partial_screen = cursor_y - (@screen_height - 1)
+ end
+ else
+ if cursor_y > (@screen_height - 1)
+ @scroll_partial_screen = cursor_y - (@screen_height - 1)
+ else
+ @scroll_partial_screen = 0
+ end
+ end
+ end
+ if @scroll_partial_screen != old_scroll_partial_screen
+ @rerender_all = true
+ end
+ else
+ if @scroll_partial_screen
+ @rerender_all = true
+ end
+ @scroll_partial_screen = nil
+ end
+ end
+
+ private def rerender_added_newline(prompt, prompt_width)
+ scroll_down(1)
+ @buffer_of_lines[@previous_line_index] = @line
+ @line = @buffer_of_lines[@line_index]
+ 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)
+ @byte_pointer = @line.bytesize
+ @highest_in_all += @highest_in_this
+ @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
+ prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines)
+ move_cursor_up(@started_from)
+ new_first_line_started_from =
+ if @line_index.zero?
+ 0
+ else
+ 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
+ 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
+ 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
+ end
+ end
+
+ private def rerender_changed_current_line
+ 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
+ move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1)
+ if diff > 0
+ scroll_down(diff)
+ move_cursor_up(all_height - 1)
+ elsif diff < 0
+ (-diff).times do
+ Reline::IOGate.move_cursor_column(0)
+ Reline::IOGate.erase_after_cursor
+ move_cursor_up(1)
+ end
+ move_cursor_up(all_height - 1)
+ else
+ move_cursor_up(all_height - 1)
+ end
+ @highest_in_all = all_height
+ back = render_whole_lines(new_lines, prompt_list || prompt, prompt_width)
+ move_cursor_up(back)
+ if @previous_line_index
+ @buffer_of_lines[@previous_line_index] = @line
+ @line = @buffer_of_lines[@line_index]
+ end
+ @first_line_started_from =
+ if @line_index.zero?
+ 0
+ else
+ calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
+ end
+ if @prompt_proc
+ prompt = prompt_list[@line_index]
+ prompt_width = calculate_width(prompt, true)
+ end
+ move_cursor_down(@first_line_started_from)
+ calculate_nearest_cursor
+ @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ move_cursor_down(@started_from)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
+ end
+
+ private def rerender_all_lines
+ move_cursor_up(@first_line_started_from + @started_from)
+ Reline::IOGate.move_cursor_column(0)
+ back = 0
+ new_buffer = whole_lines
+ prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
+ new_buffer.each_with_index do |line, index|
+ prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
+ width = prompt_width + calculate_width(line)
+ height = calculate_height_by_width(width)
+ back += height
+ end
+ old_highest_in_all = @highest_in_all
+ if @line_index.zero?
+ new_first_line_started_from = 0
+ else
+ new_first_line_started_from = calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list || prompt)
+ end
+ new_started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ calculate_scroll_partial_screen(back, new_first_line_started_from + new_started_from)
+ if @scroll_partial_screen
+ move_cursor_up(@first_line_started_from + @started_from)
+ scroll_down(@screen_height - 1)
+ move_cursor_up(@screen_height)
+ Reline::IOGate.move_cursor_column(0)
+ elsif back > old_highest_in_all
+ scroll_down(back - 1)
+ move_cursor_up(back - 1)
+ elsif back < old_highest_in_all
+ scroll_down(back)
+ Reline::IOGate.erase_after_cursor
+ (old_highest_in_all - back - 1).times do
+ scroll_down(1)
+ Reline::IOGate.erase_after_cursor
+ end
+ move_cursor_up(old_highest_in_all - 1)
+ end
+ render_whole_lines(new_buffer, prompt_list || prompt, prompt_width)
+ if @prompt_proc
+ prompt = prompt_list[@line_index]
+ prompt_width = calculate_width(prompt, true)
+ end
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
+ @highest_in_all = back
+ @first_line_started_from = new_first_line_started_from
+ @started_from = new_started_from
+ if @scroll_partial_screen
+ Reline::IOGate.move_cursor_up(@screen_height - (@first_line_started_from + @started_from - @scroll_partial_screen) - 1)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ else
+ move_cursor_down(@first_line_started_from + @started_from - back + 1)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ end
+ end
+
+ private def render_whole_lines(lines, prompt, prompt_width)
+ rendered_height = 0
+ modify_lines(lines).each_with_index do |line, index|
+ if prompt.is_a?(Array)
+ line_prompt = prompt[index]
+ prompt_width = calculate_width(line_prompt, true)
+ else
+ line_prompt = prompt
+ end
+ height = render_partial(line_prompt, prompt_width, line, rendered_height, with_control: false)
+ if index < (lines.size - 1)
+ if @scroll_partial_screen
+ if (@scroll_partial_screen - height) < rendered_height and (@scroll_partial_screen + @screen_height - 1) >= (rendered_height + height)
+ move_cursor_down(1)
+ end
else
- colored_content + scrollbar_sgr + ' ' * @block_elem_width
+ scroll_down(1)
end
+ rendered_height += height
else
- colored_content
+ rendered_height += height - 1
end
end
+ rendered_height
end
- private def modify_lines(before, complete)
- if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: complete)
+ private def render_partial(prompt, prompt_width, line_to_render, this_started_from, with_control: true)
+ visual_lines, height = split_by_width(line_to_render.nil? ? prompt : prompt + line_to_render, @screen_size.last)
+ cursor_up_from_last_line = 0
+ if @scroll_partial_screen
+ last_visual_line = this_started_from + (height - 1)
+ last_screen_line = @scroll_partial_screen + (@screen_height - 1)
+ if (@scroll_partial_screen - this_started_from) >= height
+ # Render nothing because this line is before the screen.
+ visual_lines = []
+ elsif this_started_from > last_screen_line
+ # Render nothing because this line is after the screen.
+ visual_lines = []
+ else
+ deleted_lines_before_screen = []
+ if @scroll_partial_screen > this_started_from and last_visual_line >= @scroll_partial_screen
+ # A part of visual lines are before the screen.
+ deleted_lines_before_screen = visual_lines.shift((@scroll_partial_screen - this_started_from) * 2)
+ deleted_lines_before_screen.compact!
+ end
+ if this_started_from <= last_screen_line and last_screen_line < last_visual_line
+ # A part of visual lines are after the screen.
+ visual_lines.pop((last_visual_line - last_screen_line) * 2)
+ end
+ move_cursor_up(deleted_lines_before_screen.size - @started_from)
+ cursor_up_from_last_line = @started_from - deleted_lines_before_screen.size
+ end
+ end
+ if with_control
+ if height > @highest_in_this
+ diff = height - @highest_in_this
+ scroll_down(diff)
+ @highest_in_all += diff
+ @highest_in_this = height
+ move_cursor_up(diff)
+ elsif height < @highest_in_this
+ diff = @highest_in_this - height
+ @highest_in_all -= diff
+ @highest_in_this = height
+ end
+ move_cursor_up(@started_from)
+ @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ cursor_up_from_last_line = height - 1 - @started_from
+ end
+ if Reline::Unicode::CSI_REGEXP.match?(prompt + line_to_render)
+ @output.write "\e[0m" # clear character decorations
+ end
+ visual_lines.each_with_index do |line, index|
+ Reline::IOGate.move_cursor_column(0)
+ if line.nil?
+ if calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
+ # reaches the end of line
+ if Reline::IOGate.win? and Reline::IOGate.win_legacy_console?
+ # A newline is automatically inserted if a character is rendered at
+ # eol on command prompt.
+ else
+ # When the cursor is at the end of the line and erases characters
+ # after the cursor, some terminals delete the character at the
+ # cursor position.
+ move_cursor_down(1)
+ Reline::IOGate.move_cursor_column(0)
+ end
+ else
+ Reline::IOGate.erase_after_cursor
+ move_cursor_down(1)
+ Reline::IOGate.move_cursor_column(0)
+ end
+ next
+ end
+ @output.write line
+ if Reline::IOGate.win? and Reline::IOGate.win_legacy_console? and calculate_width(line, true) == Reline::IOGate.get_screen_size.last
+ # A newline is automatically inserted if a character is rendered at eol on command prompt.
+ @rest_height -= 1 if @rest_height > 0
+ end
+ @output.flush
+ if @first_prompt
+ @first_prompt = false
+ @pre_input_hook&.call
+ end
+ end
+ unless visual_lines.empty?
+ Reline::IOGate.erase_after_cursor
+ Reline::IOGate.move_cursor_column(0)
+ end
+ if with_control
+ # Just after rendring, so the cursor is on the last line.
+ if finished?
+ Reline::IOGate.move_cursor_column(0)
+ else
+ # Moves up from bottom of lines to the cursor position.
+ move_cursor_up(cursor_up_from_last_line)
+ # This logic is buggy if a fullwidth char is wrapped because there is only one halfwidth at end of a line.
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ end
+ end
+ height
+ end
+
+ 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('') }
else
- before.map { |l| Reline::Unicode.escape_for_print(l) }
+ before
end
end
+ private def show_menu
+ scroll_down(@highest_in_all - @first_line_started_from)
+ @rerender_all = true
+ @menu_info.list.sort!.each do |item|
+ Reline::IOGate.move_cursor_column(0)
+ @output.write item
+ @output.flush
+ scroll_down(1)
+ end
+ scroll_down(@highest_in_all - 1)
+ move_cursor_up(@highest_in_all - 1 - @first_line_started_from)
+ end
+
+ private def clear_screen_buffer(prompt, prompt_list, prompt_width)
+ Reline::IOGate.clear_screen
+ back = 0
+ modify_lines(whole_lines).each_with_index do |line, index|
+ if @prompt_proc
+ pr = prompt_list[index]
+ height = render_partial(pr, calculate_width(pr), line, back, with_control: false)
+ else
+ height = render_partial(prompt, prompt_width, line, back, with_control: false)
+ end
+ if index < (@buffer_of_lines.size - 1)
+ move_cursor_down(1)
+ back += height
+ end
+ end
+ move_cursor_up(back)
+ move_cursor_down(@first_line_started_from + @started_from)
+ @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ end
+
def editing_mode
@config.editing_mode
end
- private def menu(_target, list)
- @menu_info = MenuInfo.new(list)
+ private def menu(target, list)
+ @menu_info = MenuInfo.new(target, list)
end
private def complete_internal_proc(list, is_menu)
@@ -820,7 +1315,7 @@ class Reline::LineEditor
item_mbchars = item.grapheme_clusters
end
size = [memo_mbchars.size, item_mbchars.size].min
- result = +''
+ result = ''
size.times do |i|
if @config.completion_ignore_case
if memo_mbchars[i].casecmp?(item_mbchars[i])
@@ -841,9 +1336,9 @@ class Reline::LineEditor
[target, preposing, completed, postposing]
end
- private def perform_completion(list, just_show_list)
+ private def complete(list, just_show_list = false)
case @completion_state
- when CompletionState::NORMAL
+ when CompletionState::NORMAL, CompletionState::JOURNEY
@completion_state = CompletionState::COMPLETION
when CompletionState::PERFECT_MATCH
@dig_perfect_match_proc&.(@perfect_matched)
@@ -870,80 +1365,100 @@ class Reline::LineEditor
@completion_state = CompletionState::PERFECT_MATCH
else
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
- perform_completion(list, true) if @config.show_all_if_ambiguous
end
@perfect_matched = completed
else
@completion_state = CompletionState::MENU
- perform_completion(list, true) if @config.show_all_if_ambiguous
end
if not just_show_list and target < completed
- @buffer_of_lines[@line_index] = (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")[@line_index] || 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
end
end
end
- def dialog_proc_scope_completion_journey_data
- return nil unless @completion_journey_state
- line_index = @completion_journey_state.line_index
- pre_lines = @buffer_of_lines[0...line_index].map { |line| line + "\n" }
- post_lines = @buffer_of_lines[(line_index + 1)..-1].map { |line| line + "\n" }
- DialogProcScope::CompletionJourneyData.new(
- pre_lines.join + @completion_journey_state.pre,
- @completion_journey_state.post + post_lines.join,
- @completion_journey_state.list,
- @completion_journey_state.pointer
- )
- end
-
- private def move_completed_list(direction)
- @completion_journey_state ||= retrieve_completion_journey_state
- return false unless @completion_journey_state
-
- if (delta = { up: -1, down: +1 }[direction])
- @completion_journey_state.pointer = (@completion_journey_state.pointer + delta) % @completion_journey_state.list.size
+ private def move_completed_list(list, direction)
+ case @completion_state
+ when CompletionState::NORMAL, CompletionState::COMPLETION,
+ CompletionState::MENU, CompletionState::MENU_WITH_PERFECT_MATCH
+ @completion_state = CompletionState::JOURNEY
+ result = retrieve_completion_block
+ return if result.nil?
+ preposing, target, postposing = result
+ @completion_journey_data = CompletionJourneyData.new(
+ preposing, postposing,
+ [target] + list.select{ |item| item.start_with?(target) }, 0)
+ if @completion_journey_data.list.size == 1
+ @completion_journey_data.pointer = 0
+ else
+ case direction
+ when :up
+ @completion_journey_data.pointer = @completion_journey_data.list.size - 1
+ when :down
+ @completion_journey_data.pointer = 1
+ end
+ end
+ @completion_state = CompletionState::JOURNEY
+ else
+ case direction
+ when :up
+ @completion_journey_data.pointer -= 1
+ if @completion_journey_data.pointer < 0
+ @completion_journey_data.pointer = @completion_journey_data.list.size - 1
+ end
+ when :down
+ @completion_journey_data.pointer += 1
+ if @completion_journey_data.pointer >= @completion_journey_data.list.size
+ @completion_journey_data.pointer = 0
+ end
+ end
end
- completed = @completion_journey_state.list[@completion_journey_state.pointer]
- set_current_line(@completion_journey_state.pre + completed + @completion_journey_state.post, @completion_journey_state.pre.bytesize + completed.bytesize)
- true
- end
-
- private def retrieve_completion_journey_state
- preposing, target, postposing = retrieve_completion_block
- list = call_completion_proc
- return unless list.is_a?(Array)
-
- candidates = list.select{ |item| item.start_with?(target) }
- return if candidates.empty?
-
- pre = preposing.split("\n", -1).last || ''
- post = postposing.split("\n", -1).first || ''
- CompletionJourneyState.new(
- @line_index, pre, target, post, [target] + candidates, 0
- )
+ completed = @completion_journey_data.list[@completion_journey_data.pointer]
+ new_line = (@completion_journey_data.preposing + completed + @completion_journey_data.postposing).split("\n")[@line_index]
+ @line = new_line.nil? ? String.new(encoding: @encoding) : new_line
+ line_to_pointer = (@completion_journey_data.preposing + completed).split("\n").last
+ line_to_pointer = String.new(encoding: @encoding) if line_to_pointer.nil?
+ @cursor_max = calculate_width(@line)
+ @cursor = calculate_width(line_to_pointer)
+ @byte_pointer = line_to_pointer.bytesize
end
private def run_for_operators(key, method_symbol, &block)
- if @vi_waiting_operator
+ if @waiting_operator_proc
if VI_MOTIONS.include?(method_symbol)
- old_byte_pointer = @byte_pointer
- @vi_arg = (@vi_arg || 1) * @vi_waiting_operator_arg
+ old_cursor, old_byte_pointer = @cursor, @byte_pointer
+ @vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg&.> 1
block.(true)
unless @waiting_proc
- byte_pointer_diff = @byte_pointer - old_byte_pointer
- @byte_pointer = old_byte_pointer
- method_obj = method(@vi_waiting_operator)
- wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
- cleanup_waiting
+ cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
+ @cursor, @byte_pointer = old_cursor, old_byte_pointer
+ @waiting_operator_proc.(cursor_diff, byte_pointer_diff)
+ else
+ old_waiting_proc = @waiting_proc
+ old_waiting_operator_proc = @waiting_operator_proc
+ current_waiting_operator_proc = @waiting_operator_proc
+ @waiting_proc = proc { |k|
+ old_cursor, old_byte_pointer = @cursor, @byte_pointer
+ old_waiting_proc.(k)
+ cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
+ @cursor, @byte_pointer = old_cursor, old_byte_pointer
+ current_waiting_operator_proc.(cursor_diff, byte_pointer_diff)
+ @waiting_operator_proc = old_waiting_operator_proc
+ }
end
else
# Ignores operator when not motion is given.
block.(false)
- cleanup_waiting
end
- @vi_arg = nil
+ @waiting_operator_proc = nil
+ @waiting_operator_vi_arg = nil
+ if @vi_arg
+ @rerender_all = true
+ @vi_arg = nil
+ end
else
block.(false)
end
@@ -960,7 +1475,7 @@ class Reline::LineEditor
end
def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
- if @config.editing_mode_is?(:emacs, :vi_insert) and @vi_waiting_operator.nil?
+ if @config.editing_mode_is?(:emacs, :vi_insert) and @waiting_proc.nil? and @waiting_operator_proc.nil?
not_insertion = method_symbol != :ed_insert
process_insert(force: not_insertion)
end
@@ -979,33 +1494,11 @@ class Reline::LineEditor
end
end
- private def cleanup_waiting
- @waiting_proc = nil
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- @searching_prompt = nil
- @drop_terminate_spaces = false
- end
-
private def process_key(key, method_symbol)
- if key.is_a?(Symbol)
- cleanup_waiting
- elsif @waiting_proc
- old_byte_pointer = @byte_pointer
- @waiting_proc.call(key)
- if @vi_waiting_operator
- byte_pointer_diff = @byte_pointer - old_byte_pointer
- @byte_pointer = old_byte_pointer
- method_obj = method(@vi_waiting_operator)
- wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
- cleanup_waiting
- end
- @kill_ring.process
- return
- end
-
if method_symbol and respond_to?(method_symbol, true)
method_obj = method(method_symbol)
+ else
+ method_obj = nil
end
if method_symbol and key.is_a?(Symbol)
if @vi_arg and argumentable?(method_obj)
@@ -1017,6 +1510,7 @@ class Reline::LineEditor
end
@kill_ring.process
if @vi_arg
+ @rerender_al = true
@vi_arg = nil
end
elsif @vi_arg
@@ -1027,6 +1521,8 @@ class Reline::LineEditor
run_for_operators(key, method_symbol) do |with_operator|
wrap_method_call(method_symbol, method_obj, key, with_operator)
end
+ elsif @waiting_proc
+ @waiting_proc.(key)
elsif method_obj
wrap_method_call(method_symbol, method_obj, key)
else
@@ -1034,9 +1530,13 @@ class Reline::LineEditor
end
@kill_ring.process
if @vi_arg
+ @rerender_all = true
@vi_arg = nil
end
end
+ elsif @waiting_proc
+ @waiting_proc.(key)
+ @kill_ring.process
elsif method_obj
if method_symbol == :ed_argument_digit
wrap_method_call(method_symbol, method_obj, key)
@@ -1052,6 +1552,11 @@ class Reline::LineEditor
end
private def normal_char(key)
+ method_symbol = method_obj = nil
+ if key.combined_char.is_a?(Symbol)
+ process_key(key.combined_char, key.combined_char)
+ return
+ end
@multibyte_buffer << key.combined_char
if @multibyte_buffer.size > 1
if @multibyte_buffer.dup.force_encoding(@encoding).valid_encoding?
@@ -1064,101 +1569,98 @@ class Reline::LineEditor
else # single byte
return if key.char >= 128 # maybe, first byte of multi byte
method_symbol = @config.editing_mode.get_method(key.combined_char)
- process_key(key.combined_char, method_symbol)
+ if key.with_meta and method_symbol == :ed_unassigned
+ # 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
@multibyte_buffer.clear
end
- if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
- byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer)
+ if @config.editing_mode_is?(:vi_command) and @cursor > 0 and @cursor == @cursor_max
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
@byte_pointer -= byte_size
- end
- end
-
- def update(key)
- modified = input_key(key)
- unless @in_pasting
- scroll_into_view
- @just_cursor_moving = !modified
- update_dialogs(key)
- @just_cursor_moving = false
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
end
end
def input_key(key)
- save_old_buffer
+ @last_key = key
@config.reset_oneshot_key_bindings
@dialogs.each do |dialog|
if key.char.instance_of?(Symbol) and key.char == dialog.name
return
end
end
+ @just_cursor_moving = nil
if key.char.nil?
- process_insert(force: true)
- @eof = buffer_empty?
+ if @first_char
+ @line = nil
+ end
finish
return
end
- @completion_occurs = false
-
- if key.char.is_a?(Symbol)
+ old_line = @line.dup
+ @first_char = false
+ completion_occurs = false
+ if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
+ unless @config.disable_completion
+ result = call_completion_proc
+ if result.is_a?(Array)
+ completion_occurs = true
+ process_insert
+ if @config.autocompletion
+ move_completed_list(result, :down)
+ else
+ complete(result)
+ end
+ end
+ end
+ elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up
+ if not @config.disable_completion and @config.autocompletion
+ result = call_completion_proc
+ if result.is_a?(Array)
+ completion_occurs = true
+ process_insert
+ move_completed_list(result, :up)
+ end
+ end
+ elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
+ unless @config.disable_completion
+ result = call_completion_proc
+ if result.is_a?(Array)
+ completion_occurs = true
+ process_insert
+ move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
+ end
+ end
+ elsif Symbol === key.char and respond_to?(key.char, true)
process_key(key.char, key.char)
else
normal_char(key)
end
-
- @prev_action_state, @next_action_state = @next_action_state, NullActionState
-
- unless @completion_occurs
+ unless completion_occurs
@completion_state = CompletionState::NORMAL
- @completion_journey_state = nil
- end
-
- push_input_lines unless @undoing
- @undoing = false
-
- if @in_pasting
- clear_dialogs
- return
- end
-
- modified = @old_buffer_of_lines != @buffer_of_lines
- if !@completion_occurs && modified && !@config.disable_completion && @config.autocompletion
- # Auto complete starts only when edited
- process_insert(force: true)
- @completion_journey_state = retrieve_completion_journey_state
+ @completion_journey_data = nil
end
- modified
- end
-
- def save_old_buffer
- @old_buffer_of_lines = @buffer_of_lines.dup
- end
-
- def push_input_lines
- if @old_buffer_of_lines == @buffer_of_lines
- @input_lines[@input_lines_position] = [@buffer_of_lines.dup, @byte_pointer, @line_index]
+ if not @in_pasting and @just_cursor_moving.nil?
+ if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line
+ @just_cursor_moving = true
+ elsif @previous_line_index.nil? and @buffer_of_lines[@line_index] == @line and old_line == @line
+ @just_cursor_moving = true
+ else
+ @just_cursor_moving = false
+ end
else
- @input_lines = @input_lines[0..@input_lines_position]
- @input_lines_position += 1
- @input_lines.push([@buffer_of_lines.dup, @byte_pointer, @line_index])
- end
- trim_input_lines
- end
-
- MAX_INPUT_LINES = 100
- def trim_input_lines
- if @input_lines.size > MAX_INPUT_LINES
- @input_lines.shift
- @input_lines_position -= 1
- end
- end
-
- def scroll_into_view
- _wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
- if wrapped_cursor_y < screen_scroll_top
- @scroll_partial_screen = wrapped_cursor_y
+ @just_cursor_moving = false
end
- if wrapped_cursor_y >= screen_scroll_top + screen_height
- @scroll_partial_screen = wrapped_cursor_y - screen_height + 1
+ if @is_multiline and @auto_indent_proc and not simplified_rendering?
+ process_auto_indent
end
end
@@ -1192,52 +1694,46 @@ class Reline::LineEditor
result
end
- private def process_auto_indent(line_index = @line_index, cursor_dependent: true, add_newline: false)
- return if @in_pasting
- return unless @auto_indent_proc
-
- line = @buffer_of_lines[line_index]
- byte_pointer = cursor_dependent && @line_index == line_index ? @byte_pointer : line.bytesize
- new_indent = @auto_indent_proc.(@buffer_of_lines.take(line_index + 1).push(''), line_index, byte_pointer, add_newline)
- return unless new_indent
+ private def process_auto_indent
+ 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(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_line = ' ' * new_indent + line.lstrip
- @buffer_of_lines[line_index] = new_line
- if @line_index == line_index
- indent_diff = new_line.bytesize - line.bytesize
- @byte_pointer = [@byte_pointer + indent_diff, 0].max
- end
- end
-
- def line()
- @buffer_of_lines.join("\n") unless eof?
- end
-
- def current_line
- @buffer_of_lines[@line_index]
- end
-
- def set_current_line(line, byte_pointer = nil)
- cursor = current_byte_pointer_cursor
- @buffer_of_lines[@line_index] = line
- if byte_pointer
- @byte_pointer = byte_pointer
- else
- calculate_nearest_cursor(cursor)
+ new_indent = nil
+ result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[-2].size + 1), false)
+ if result
+ new_indent = result
+ end
+ if new_indent&.>= 0
+ @line = ' ' * new_indent + @line.lstrip
+ end
end
- process_auto_indent
- end
-
- def set_current_lines(lines, byte_pointer = nil, line_index = 0)
- cursor = current_byte_pointer_cursor
- @buffer_of_lines = lines
- @line_index = line_index
- if byte_pointer
- @byte_pointer = byte_pointer
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
else
- calculate_nearest_cursor(cursor)
+ 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
+ @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
+ @cursor = new_indent
+ @byte_pointer = new_indent
+ else
+ @line = ' ' * new_indent + @line.lstrip
+ @cursor += new_indent - prev_indent
+ @byte_pointer += new_indent - prev_indent
+ end
end
- process_auto_indent
+ @check_new_auto_indent = false
end
def retrieve_completion_block(set_completion_quote_character = false)
@@ -1251,7 +1747,7 @@ class Reline::LineEditor
else
quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
end
- before = current_line.byteslice(0, @byte_pointer)
+ before = @line.byteslice(0, @byte_pointer)
rest = nil
break_pointer = nil
quote = nil
@@ -1259,7 +1755,7 @@ class Reline::LineEditor
escaped_quote = nil
i = 0
while i < @byte_pointer do
- slice = current_line.byteslice(i, @byte_pointer - i)
+ slice = @line.byteslice(i, @byte_pointer - i)
unless slice.valid_encoding?
i += 1
next
@@ -1281,15 +1777,15 @@ class Reline::LineEditor
elsif word_break_regexp and not quote and slice =~ word_break_regexp
rest = $'
i += 1
- before = current_line.byteslice(i, @byte_pointer - i)
+ before = @line.byteslice(i, @byte_pointer - i)
break_pointer = i
else
i += 1
end
end
- postposing = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
+ postposing = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
if rest
- preposing = current_line.byteslice(0, break_pointer)
+ preposing = @line.byteslice(0, break_pointer)
target = rest
if set_completion_quote_character and quote
Reline.core.instance_variable_set(:@completion_quote_character, quote)
@@ -1300,97 +1796,133 @@ class Reline::LineEditor
else
preposing = ''
if break_pointer
- preposing = current_line.byteslice(0, break_pointer)
+ preposing = @line.byteslice(0, break_pointer)
else
preposing = ''
end
target = before
end
- lines = whole_lines
- if @line_index > 0
- preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
- end
- if (lines.size - 1) > @line_index
- postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
+ if @is_multiline
+ 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
+ if (lines.size - 1) > @line_index
+ postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
+ end
end
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
end
def confirm_multiline_termination
temp_buffer = @buffer_of_lines.dup
+ if @previous_line_index and @line_index == (@buffer_of_lines.size - 1)
+ temp_buffer[@previous_line_index] = @line
+ else
+ temp_buffer[@line_index] = @line
+ end
@confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
end
- def insert_multiline_text(text)
- save_old_buffer
- pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
- post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
- lines = (pre + text.gsub(/\r\n?/, "\n") + post).split("\n", -1)
- lines << '' if lines.empty?
- @buffer_of_lines[@line_index, 1] = lines
- @line_index += lines.size - 1
- @byte_pointer = @buffer_of_lines[@line_index].bytesize - post.bytesize
- push_input_lines
- end
-
def insert_text(text)
- if @buffer_of_lines[@line_index].bytesize == @byte_pointer
- @buffer_of_lines[@line_index] += text
+ width = calculate_width(text)
+ if @cursor == @cursor_max
+ @line += text
else
- @buffer_of_lines[@line_index] = byteinsert(@buffer_of_lines[@line_index], @byte_pointer, text)
+ @line = byteinsert(@line, @byte_pointer, text)
end
@byte_pointer += text.bytesize
- process_auto_indent
+ @cursor += width
+ @cursor_max += width
end
def delete_text(start = nil, length = nil)
if start.nil? and length.nil?
- if @buffer_of_lines.size == 1
- @buffer_of_lines[@line_index] = ''
- @byte_pointer = 0
- elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
- @buffer_of_lines.pop
- @line_index -= 1
- @byte_pointer = 0
- elsif @line_index < (@buffer_of_lines.size - 1)
- @buffer_of_lines.delete_at(@line_index)
+ if @is_multiline
+ if @buffer_of_lines.size == 1
+ @line&.clear
+ @byte_pointer = 0
+ @cursor = 0
+ @cursor_max = 0
+ elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
+ @buffer_of_lines.pop
+ @line_index -= 1
+ @line = @buffer_of_lines[@line_index]
+ @byte_pointer = 0
+ @cursor = 0
+ @cursor_max = calculate_width(@line)
+ elsif @line_index < (@buffer_of_lines.size - 1)
+ @buffer_of_lines.delete_at(@line_index)
+ @line = @buffer_of_lines[@line_index]
+ @byte_pointer = 0
+ @cursor = 0
+ @cursor_max = calculate_width(@line)
+ end
+ else
+ @line&.clear
@byte_pointer = 0
+ @cursor = 0
+ @cursor_max = 0
end
elsif not start.nil? and not length.nil?
- if current_line
- before = current_line.byteslice(0, start)
- after = current_line.byteslice(start + length, current_line.bytesize)
- set_current_line(before + after)
+ if @line
+ before = @line.byteslice(0, start)
+ after = @line.byteslice(start + length, @line.bytesize)
+ @line = before + after
+ @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
+ str = @line.byteslice(0, @byte_pointer)
+ @cursor = calculate_width(str)
+ @cursor_max = calculate_width(@line)
end
elsif start.is_a?(Range)
range = start
first = range.first
last = range.last
- last = current_line.bytesize - 1 if last > current_line.bytesize
- last += current_line.bytesize if last < 0
- first += current_line.bytesize if first < 0
+ last = @line.bytesize - 1 if last > @line.bytesize
+ last += @line.bytesize if last < 0
+ first += @line.bytesize if first < 0
range = range.exclude_end? ? first...last : first..last
- line = current_line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(@encoding)
- set_current_line(line)
+ @line = @line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(@encoding)
+ @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
+ str = @line.byteslice(0, @byte_pointer)
+ @cursor = calculate_width(str)
+ @cursor_max = calculate_width(@line)
else
- set_current_line(current_line.byteslice(0, start))
+ @line = @line.byteslice(0, start)
+ @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
+ str = @line.byteslice(0, @byte_pointer)
+ @cursor = calculate_width(str)
+ @cursor_max = calculate_width(@line)
end
end
def byte_pointer=(val)
@byte_pointer = val
+ str = @line.byteslice(0, @byte_pointer)
+ @cursor = calculate_width(str)
+ @cursor_max = calculate_width(@line)
end
- def whole_lines
- @buffer_of_lines.dup
+ def whole_lines(index: @line_index, line: @line)
+ temp_lines = @buffer_of_lines.dup
+ temp_lines[index] = line
+ temp_lines
end
def whole_buffer
- whole_lines.join("\n")
- end
-
- private def buffer_empty?
- current_line.empty? and @buffer_of_lines.size == 1
+ if @buffer_of_lines.size == 1 and @line.nil?
+ nil
+ else
+ if @previous_line_index
+ whole_lines(index: @previous_line_index, line: @line).join("\n")
+ else
+ whole_lines.join("\n")
+ end
+ end
end
def finished?
@@ -1399,6 +1931,7 @@ class Reline::LineEditor
def finish
@finished = true
+ @rerender_all = true
@config.reset
end
@@ -1420,65 +1953,40 @@ 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
private def key_newline(key)
if @is_multiline
- next_line = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
- cursor_line = current_line.byteslice(0, @byte_pointer)
- insert_new_line(cursor_line, next_line)
- end
- end
-
- private def complete(_key)
- return if @config.disable_completion
-
- process_insert(force: true)
- if @config.autocompletion
- @completion_state = CompletionState::NORMAL
- @completion_occurs = move_completed_list(:down)
- else
- @completion_journey_state = nil
- result = call_completion_proc
- if result.is_a?(Array)
- @completion_occurs = true
- perform_completion(result, false)
+ if (@buffer_of_lines.size - 1) == @line_index and @line.bytesize == @byte_pointer
+ @add_newline_to_end_of_buffer = true
end
+ next_line = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
+ cursor_line = @line.byteslice(0, @byte_pointer)
+ insert_new_line(cursor_line, next_line)
+ @cursor = 0
+ @check_new_auto_indent = true unless @in_pasting
end
end
- private def completion_journey_move(direction)
- return if @config.disable_completion
-
- process_insert(force: true)
- @completion_state = CompletionState::NORMAL
- @completion_occurs = move_completed_list(direction)
- end
-
- private def menu_complete(_key)
- completion_journey_move(:down)
- end
-
- private def menu_complete_backward(_key)
- completion_journey_move(:up)
- end
-
- private def completion_journey_up(_key)
- completion_journey_move(:up) if @config.autocompletion
- end
-
# Editline:: +ed-unassigned+ This editor command always results in an error.
# GNU Readline:: There is no corresponding macro.
private def ed_unassigned(key) end # do nothing
private def process_insert(force: false)
return if @continuous_insertion_buffer.empty? or (@in_pasting and not force)
- insert_text(@continuous_insertion_buffer)
+ width = Reline::Unicode.calculate_width(@continuous_insertion_buffer)
+ bytesize = @continuous_insertion_buffer.bytesize
+ if @cursor == @cursor_max
+ @line += @continuous_insertion_buffer
+ else
+ @line = byteinsert(@line, @byte_pointer, @continuous_insertion_buffer)
+ end
+ @byte_pointer += bytesize
+ @cursor += width
+ @cursor_max += width
@continuous_insertion_buffer.clear
end
@@ -1496,6 +2004,9 @@ class Reline::LineEditor
# million.
# GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
private def ed_insert(key)
+ str = nil
+ width = nil
+ bytesize = nil
if key.instance_of?(String)
begin
key.encode(Encoding::UTF_8)
@@ -1503,6 +2014,7 @@ class Reline::LineEditor
return
end
str = key
+ bytesize = key.bytesize
else
begin
key.chr.encode(Encoding::UTF_8)
@@ -1510,6 +2022,7 @@ class Reline::LineEditor
return
end
str = key.chr
+ bytesize = 1
end
if @in_pasting
@continuous_insertion_buffer << str
@@ -1517,8 +2030,28 @@ class Reline::LineEditor
elsif not @continuous_insertion_buffer.empty?
process_insert
end
-
- insert_text(str)
+ width = Reline::Unicode.get_mbchar_width(str)
+ if @cursor == @cursor_max
+ @line += str
+ else
+ @line = byteinsert(@line, @byte_pointer, str)
+ end
+ last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
+ @byte_pointer += bytesize
+ last_mbchar = @line.byteslice((@byte_pointer - bytesize - last_byte_size), last_byte_size)
+ combined_char = last_mbchar + str
+ if last_byte_size != 0 and combined_char.grapheme_clusters.size == 1
+ # combined char
+ last_mbchar_width = Reline::Unicode.get_mbchar_width(last_mbchar)
+ combined_char_width = Reline::Unicode.get_mbchar_width(combined_char)
+ if combined_char_width > last_mbchar_width
+ width = combined_char_width - last_mbchar_width
+ else
+ width = 0
+ end
+ end
+ @cursor += width
+ @cursor_max += width
end
alias_method :ed_digit, :ed_insert
alias_method :self_insert, :ed_insert
@@ -1540,11 +2073,18 @@ class Reline::LineEditor
alias_method :quoted_insert, :ed_quoted_insert
private def ed_next_char(key, arg: 1)
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- if (@byte_pointer < current_line.bytesize)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ if (@byte_pointer < @line.bytesize)
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor += width if width
@byte_pointer += byte_size
- elsif @config.editing_mode_is?(:emacs) and @byte_pointer == current_line.bytesize and @line_index < @buffer_of_lines.size - 1
+ elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == @line.bytesize and @line_index < @buffer_of_lines.size - 1
+ next_line = @buffer_of_lines[@line_index + 1]
+ @cursor = 0
@byte_pointer = 0
+ @cursor_max = calculate_width(next_line)
+ @previous_line_index = @line_index
@line_index += 1
end
arg -= 1
@@ -1553,12 +2093,19 @@ class Reline::LineEditor
alias_method :forward_char, :ed_next_char
private def ed_prev_char(key, arg: 1)
- if @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
+ if @cursor > 0
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
@byte_pointer -= byte_size
- elsif @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
+ elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
+ prev_line = @buffer_of_lines[@line_index - 1]
+ @cursor = calculate_width(prev_line)
+ @byte_pointer = prev_line.bytesize
+ @cursor_max = calculate_width(prev_line)
+ @previous_line_index = @line_index
@line_index -= 1
- @byte_pointer = current_line.bytesize
end
arg -= 1
ed_prev_char(key, arg: arg) if arg > 0
@@ -1566,109 +2113,157 @@ class Reline::LineEditor
alias_method :backward_char, :ed_prev_char
private def vi_first_print(key)
- @byte_pointer, = Reline::Unicode.vi_first_print(current_line)
+ @byte_pointer, @cursor = Reline::Unicode.vi_first_print(@line)
end
private def ed_move_to_beg(key)
- @byte_pointer = 0
+ @byte_pointer = @cursor = 0
end
alias_method :beginning_of_line, :ed_move_to_beg
- alias_method :vi_zero, :ed_move_to_beg
private def ed_move_to_end(key)
- @byte_pointer = current_line.bytesize
+ @byte_pointer = 0
+ @cursor = 0
+ byte_size = 0
+ while @byte_pointer < @line.bytesize
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ if byte_size > 0
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ @cursor += Reline::Unicode.get_mbchar_width(mbchar)
+ end
+ @byte_pointer += byte_size
+ end
end
alias_method :end_of_line, :ed_move_to_end
- private def generate_searcher(search_key)
- search_word = String.new(encoding: @encoding)
- multibyte_buf = String.new(encoding: 'ASCII-8BIT')
- hit_pointer = nil
- lambda do |key|
- search_again = false
- case key
- when "\C-h".ord, "\C-?".ord
- grapheme_clusters = search_word.grapheme_clusters
- if grapheme_clusters.size > 0
- grapheme_clusters.pop
- search_word = grapheme_clusters.join
- end
- when "\C-r".ord, "\C-s".ord
- search_again = true if search_key == key
- search_key = key
- else
- multibyte_buf << key
- if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
- search_word << multibyte_buf.dup.force_encoding(@encoding)
- multibyte_buf.clear
- end
+ private def generate_searcher
+ Fiber.new do |first_key|
+ prev_search_key = first_key
+ search_word = String.new(encoding: @encoding)
+ multibyte_buf = String.new(encoding: 'ASCII-8BIT')
+ last_hit = nil
+ case first_key
+ when "\C-r".ord
+ prompt_name = 'reverse-i-search'
+ when "\C-s".ord
+ prompt_name = 'i-search'
end
- hit = nil
- if not search_word.empty? and @line_backup_in_history&.include?(search_word)
- hit_pointer = Reline::HISTORY.size
- hit = @line_backup_in_history
- else
- if search_again
- if search_word.empty? and Reline.last_incremental_search
- search_word = Reline.last_incremental_search
+ loop do
+ key = Fiber.yield(search_word)
+ search_again = false
+ case key
+ when -1 # determined
+ Reline.last_incremental_search = search_word
+ break
+ when "\C-h".ord, "\C-?".ord
+ grapheme_clusters = search_word.grapheme_clusters
+ if grapheme_clusters.size > 0
+ grapheme_clusters.pop
+ search_word = grapheme_clusters.join
end
- if @history_pointer
- case search_key
+ when "\C-r".ord, "\C-s".ord
+ search_again = true if prev_search_key == key
+ prev_search_key = key
+ else
+ multibyte_buf << key
+ if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
+ search_word << multibyte_buf.dup.force_encoding(@encoding)
+ multibyte_buf.clear
+ end
+ end
+ hit = nil
+ if not search_word.empty? and @line_backup_in_history&.include?(search_word)
+ @history_pointer = nil
+ hit = @line_backup_in_history
+ else
+ if search_again
+ if search_word.empty? and Reline.last_incremental_search
+ search_word = Reline.last_incremental_search
+ end
+ if @history_pointer
+ case prev_search_key
+ when "\C-r".ord
+ history_pointer_base = 0
+ history = Reline::HISTORY[0..(@history_pointer - 1)]
+ when "\C-s".ord
+ history_pointer_base = @history_pointer + 1
+ history = Reline::HISTORY[(@history_pointer + 1)..-1]
+ end
+ else
+ history_pointer_base = 0
+ history = Reline::HISTORY
+ end
+ elsif @history_pointer
+ case prev_search_key
when "\C-r".ord
history_pointer_base = 0
- history = Reline::HISTORY[0..(@history_pointer - 1)]
+ history = Reline::HISTORY[0..@history_pointer]
when "\C-s".ord
- history_pointer_base = @history_pointer + 1
- history = Reline::HISTORY[(@history_pointer + 1)..-1]
+ history_pointer_base = @history_pointer
+ history = Reline::HISTORY[@history_pointer..-1]
end
else
history_pointer_base = 0
history = Reline::HISTORY
end
- elsif @history_pointer
- case search_key
+ case prev_search_key
when "\C-r".ord
- history_pointer_base = 0
- history = Reline::HISTORY[0..@history_pointer]
+ hit_index = history.rindex { |item|
+ item.include?(search_word)
+ }
when "\C-s".ord
- history_pointer_base = @history_pointer
- history = Reline::HISTORY[@history_pointer..-1]
+ hit_index = history.index { |item|
+ item.include?(search_word)
+ }
+ end
+ if hit_index
+ @history_pointer = history_pointer_base + hit_index
+ hit = Reline::HISTORY[@history_pointer]
end
- else
- history_pointer_base = 0
- history = Reline::HISTORY
end
- case search_key
+ case prev_search_key
when "\C-r".ord
- hit_index = history.rindex { |item|
- item.include?(search_word)
- }
+ prompt_name = 'reverse-i-search'
when "\C-s".ord
- hit_index = history.index { |item|
- item.include?(search_word)
- }
+ prompt_name = 'i-search'
end
- if hit_index
- hit_pointer = history_pointer_base + hit_index
- hit = Reline::HISTORY[hit_pointer]
+ if hit
+ if @is_multiline
+ @buffer_of_lines = hit.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @byte_pointer = @line.bytesize
+ @cursor = @cursor_max = calculate_width(@line)
+ @rerender_all = true
+ @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
+ else
+ @line = hit
+ @searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
+ end
+ last_hit = hit
+ else
+ if @is_multiline
+ @rerender_all = true
+ @searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
+ else
+ @searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
+ end
end
end
- case search_key
- when "\C-r".ord
- prompt_name = 'reverse-i-search'
- when "\C-s".ord
- prompt_name = 'i-search'
- end
- prompt_name = "failed #{prompt_name}" unless hit
- [search_word, prompt_name, hit_pointer]
end
end
private def incremental_search_history(key)
unless @history_pointer
- @line_backup_in_history = whole_buffer
+ if @is_multiline
+ @line_backup_in_history = whole_buffer
+ else
+ @line_backup_in_history = @line
+ end
end
- searcher = generate_searcher(key)
+ searcher = generate_searcher
+ searcher.resume(key)
@searching_prompt = "(reverse-i-search)`': "
termination_keys = ["\C-j".ord]
termination_keys.concat(@config.isearch_terminators&.chars&.map(&:ord)) if @config.isearch_terminators
@@ -1680,41 +2275,67 @@ class Reline::LineEditor
else
buffer = @line_backup_in_history
end
- @buffer_of_lines = buffer.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = @buffer_of_lines.size - 1
+ if @is_multiline
+ @buffer_of_lines = buffer.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ @line = buffer
+ end
@searching_prompt = nil
@waiting_proc = nil
- @byte_pointer = 0
+ @cursor_max = calculate_width(@line)
+ @cursor = @byte_pointer = 0
+ @rerender_all = true
+ @cached_prompt_list = nil
+ searcher.resume(-1)
when "\C-g".ord
- @buffer_of_lines = @line_backup_in_history.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = @buffer_of_lines.size - 1
- move_history(nil, line: :end, cursor: :end, save_buffer: false)
+ if @is_multiline
+ @buffer_of_lines = @line_backup_in_history.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ @line = @line_backup_in_history
+ end
+ @history_pointer = nil
@searching_prompt = nil
@waiting_proc = nil
- @byte_pointer = 0
+ @line_backup_in_history = nil
+ @cursor_max = calculate_width(@line)
+ @cursor = @byte_pointer = 0
+ @rerender_all = true
else
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
- search_word, prompt_name, hit_pointer = searcher.call(k)
- Reline.last_incremental_search = search_word
- @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
- @searching_prompt += ': ' unless @is_multiline
- move_history(hit_pointer, line: :end, cursor: :end, save_buffer: false) if hit_pointer
+ searcher.resume(k)
else
if @history_pointer
line = Reline::HISTORY[@history_pointer]
else
line = @line_backup_in_history
end
- @line_backup_in_history = whole_buffer
- @buffer_of_lines = line.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = @buffer_of_lines.size - 1
+ if @is_multiline
+ @line_backup_in_history = whole_buffer
+ @buffer_of_lines = line.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ @line_backup_in_history = @line
+ @line = line
+ end
@searching_prompt = nil
@waiting_proc = nil
- @byte_pointer = 0
+ @cursor_max = calculate_width(@line)
+ @cursor = @byte_pointer = 0
+ @rerender_all = true
+ @cached_prompt_list = nil
+ searcher.resume(-1)
end
end
}
@@ -1730,97 +2351,199 @@ class Reline::LineEditor
end
alias_method :forward_search_history, :vi_search_next
- private def search_history(prefix, pointer_range)
- pointer_range.each do |pointer|
- lines = Reline::HISTORY[pointer].split("\n")
- lines.each_with_index do |line, index|
- return [pointer, index] if line.start_with?(prefix)
- end
- end
- nil
- end
-
private def ed_search_prev_history(key, arg: 1)
- substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
- return if @history_pointer == 0
- return if @history_pointer.nil? && substr.empty? && !current_line.empty?
-
- history_range = 0...(@history_pointer || Reline::HISTORY.size)
- h_pointer, line_index = search_history(substr, history_range.reverse_each)
- return unless h_pointer
- move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
+ history = nil
+ h_pointer = nil
+ line_no = nil
+ substr = @line.slice(0, @byte_pointer)
+ if @history_pointer.nil?
+ return if not @line.empty? and substr.empty?
+ history = Reline::HISTORY
+ elsif @history_pointer.zero?
+ history = nil
+ h_pointer = nil
+ else
+ history = Reline::HISTORY.slice(0, @history_pointer)
+ end
+ return if history.nil?
+ if @is_multiline
+ h_pointer = history.rindex { |h|
+ h.split("\n").each_with_index { |l, i|
+ if l.start_with?(substr)
+ line_no = i
+ break
+ end
+ }
+ not line_no.nil?
+ }
+ else
+ h_pointer = history.rindex { |l|
+ l.start_with?(substr)
+ }
+ end
+ return if h_pointer.nil?
+ @history_pointer = h_pointer
+ if @is_multiline
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = line_no
+ @line = @buffer_of_lines[@line_index]
+ @rerender_all = true
+ else
+ @line = Reline::HISTORY[@history_pointer]
+ end
+ @cursor_max = calculate_width(@line)
arg -= 1
- set_next_action_state(:search_history, :empty) if substr.empty?
ed_search_prev_history(key, arg: arg) if arg > 0
end
alias_method :history_search_backward, :ed_search_prev_history
private def ed_search_next_history(key, arg: 1)
- substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
- return if @history_pointer.nil?
-
- history_range = @history_pointer + 1...Reline::HISTORY.size
- h_pointer, line_index = search_history(substr, history_range)
- return if h_pointer.nil? and not substr.empty?
-
- move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
- arg -= 1
- set_next_action_state(:search_history, :empty) if substr.empty?
- ed_search_next_history(key, arg: arg) if arg > 0
- end
- alias_method :history_search_forward, :ed_search_next_history
-
- private def move_history(history_pointer, line:, cursor:, save_buffer: true)
- history_pointer ||= Reline::HISTORY.size
- return if history_pointer < 0 || history_pointer > Reline::HISTORY.size
- old_history_pointer = @history_pointer || Reline::HISTORY.size
- if old_history_pointer == Reline::HISTORY.size
- @line_backup_in_history = save_buffer ? whole_buffer : ''
+ substr = @line.slice(0, @byte_pointer)
+ if @history_pointer.nil?
+ return
+ elsif @history_pointer == (Reline::HISTORY.size - 1) and not substr.empty?
+ return
+ end
+ history = Reline::HISTORY.slice((@history_pointer + 1)..-1)
+ h_pointer = nil
+ line_no = nil
+ if @is_multiline
+ h_pointer = history.index { |h|
+ h.split("\n").each_with_index { |l, i|
+ if l.start_with?(substr)
+ line_no = i
+ break
+ end
+ }
+ not line_no.nil?
+ }
else
- Reline::HISTORY[old_history_pointer] = whole_buffer if save_buffer
+ h_pointer = history.index { |l|
+ l.start_with?(substr)
+ }
end
- if history_pointer == Reline::HISTORY.size
- buf = @line_backup_in_history
- @history_pointer = @line_backup_in_history = nil
+ h_pointer += @history_pointer + 1 if h_pointer and @history_pointer
+ return if h_pointer.nil? and not substr.empty?
+ @history_pointer = h_pointer
+ if @is_multiline
+ if @history_pointer.nil? and substr.empty?
+ @buffer_of_lines = []
+ @line_index = 0
+ else
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @line_index = line_no
+ end
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line = @buffer_of_lines[@line_index]
+ @rerender_all = true
else
- buf = Reline::HISTORY[history_pointer]
- @history_pointer = history_pointer
+ if @history_pointer.nil? and substr.empty?
+ @line = ''
+ else
+ @line = Reline::HISTORY[@history_pointer]
+ end
end
- @buffer_of_lines = buf.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = line == :start ? 0 : line == :end ? @buffer_of_lines.size - 1 : line
- @byte_pointer = cursor == :start ? 0 : cursor == :end ? current_line.bytesize : cursor
+ @cursor_max = calculate_width(@line)
+ arg -= 1
+ ed_search_next_history(key, arg: arg) if arg > 0
end
+ alias_method :history_search_forward, :ed_search_next_history
private def ed_prev_history(key, arg: 1)
- if @line_index > 0
- cursor = current_byte_pointer_cursor
+ if @is_multiline and @line_index > 0
+ @previous_line_index = @line_index
@line_index -= 1
- calculate_nearest_cursor(cursor)
return
end
- move_history(
- (@history_pointer || Reline::HISTORY.size) - 1,
- line: :end,
- cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
- )
+ if Reline::HISTORY.empty?
+ return
+ end
+ if @history_pointer.nil?
+ @history_pointer = Reline::HISTORY.size - 1
+ if @is_multiline
+ @line_backup_in_history = whole_buffer
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ @line_backup_in_history = @line
+ @line = Reline::HISTORY[@history_pointer]
+ end
+ elsif @history_pointer.zero?
+ return
+ else
+ if @is_multiline
+ Reline::HISTORY[@history_pointer] = whole_buffer
+ @history_pointer -= 1
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ Reline::HISTORY[@history_pointer] = @line
+ @history_pointer -= 1
+ @line = Reline::HISTORY[@history_pointer]
+ end
+ end
+ if @config.editing_mode_is?(:emacs, :vi_insert)
+ @cursor_max = @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ elsif @config.editing_mode_is?(:vi_command)
+ @byte_pointer = @cursor = 0
+ @cursor_max = calculate_width(@line)
+ end
arg -= 1
ed_prev_history(key, arg: arg) if arg > 0
end
alias_method :previous_history, :ed_prev_history
private def ed_next_history(key, arg: 1)
- if @line_index < (@buffer_of_lines.size - 1)
- cursor = current_byte_pointer_cursor
+ if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
+ @previous_line_index = @line_index
@line_index += 1
- calculate_nearest_cursor(cursor)
return
end
- move_history(
- (@history_pointer || Reline::HISTORY.size) + 1,
- line: :start,
- cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
- )
+ if @history_pointer.nil?
+ return
+ elsif @history_pointer == (Reline::HISTORY.size - 1)
+ if @is_multiline
+ @history_pointer = nil
+ @buffer_of_lines = @line_backup_in_history.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = 0
+ @line = @buffer_of_lines.first
+ @rerender_all = true
+ else
+ @history_pointer = nil
+ @line = @line_backup_in_history
+ end
+ else
+ if @is_multiline
+ Reline::HISTORY[@history_pointer] = whole_buffer
+ @history_pointer += 1
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = 0
+ @line = @buffer_of_lines.first
+ @rerender_all = true
+ else
+ Reline::HISTORY[@history_pointer] = @line
+ @history_pointer += 1
+ @line = Reline::HISTORY[@history_pointer]
+ end
+ end
+ @line = '' unless @line
+ if @config.editing_mode_is?(:emacs, :vi_insert)
+ @cursor_max = @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ elsif @config.editing_mode_is?(:vi_command)
+ @byte_pointer = @cursor = 0
+ @cursor_max = calculate_width(@line)
+ end
arg -= 1
ed_next_history(key, arg: arg) if arg > 0
end
@@ -1845,29 +2568,40 @@ class Reline::LineEditor
end
else
# should check confirm_multiline_termination to finish?
+ @previous_line_index = @line_index
@line_index = @buffer_of_lines.size - 1
- @byte_pointer = current_line.bytesize
finish
end
end
else
+ if @history_pointer
+ Reline::HISTORY[@history_pointer] = @line
+ @history_pointer = nil
+ end
finish
end
end
private def em_delete_prev_char(key, arg: 1)
- arg.times do
- if @byte_pointer == 0 and @line_index > 0
- @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
- @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
- @line_index -= 1
- elsif @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
- line, = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
- set_current_line(line, @byte_pointer - byte_size)
- end
+ if @is_multiline and @cursor == 0 and @line_index > 0
+ @buffer_of_lines[@line_index] = @line
+ @cursor = calculate_width(@buffer_of_lines[@line_index - 1])
+ @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
+ @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
+ @line_index -= 1
+ @line = @buffer_of_lines[@line_index]
+ @cursor_max = calculate_width(@line)
+ @rerender_all = true
+ elsif @cursor > 0
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
+ @byte_pointer -= byte_size
+ @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
+ @cursor_max -= width
end
- process_auto_indent
+ arg -= 1
+ em_delete_prev_char(key, arg: arg) if arg > 0
end
alias_method :backward_delete_char, :em_delete_prev_char
@@ -1877,23 +2611,23 @@ class Reline::LineEditor
# the line. With a negative numeric argument, kill backward
# from the cursor to the beginning of the current line.
private def ed_kill_line(key)
- if current_line.bytesize > @byte_pointer
- line, deleted = byteslice!(current_line, @byte_pointer, current_line.bytesize - @byte_pointer)
- set_current_line(line, line.bytesize)
+ if @line.bytesize > @byte_pointer
+ @line, deleted = byteslice!(@line, @byte_pointer, @line.bytesize - @byte_pointer)
+ @byte_pointer = @line.bytesize
+ @cursor = @cursor_max = calculate_width(@line)
@kill_ring.append(deleted)
- elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
- set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
+ elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1
+ @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ @line += @buffer_of_lines.delete_at(@line_index + 1)
+ @cursor_max = calculate_width(@line)
+ @buffer_of_lines[@line_index] = @line
+ @rerender_all = true
+ @rest_height += 1
end
end
alias_method :kill_line, :ed_kill_line
- # Editline:: +vi_change_to_eol+ (vi command: +C+) + Kill and change from the cursor to the end of the line.
- private def vi_change_to_eol(key)
- ed_kill_line(key)
-
- @config.editing_mode = :vi_insert
- end
-
# Editline:: +vi-kill-line-prev+ (vi: +Ctrl-U+) Delete the string from the
# beginning of the edit buffer to the cursor and save it to the
# cut buffer.
@@ -1901,9 +2635,11 @@ class Reline::LineEditor
# to the beginning of the current line.
private def vi_kill_line_prev(key)
if @byte_pointer > 0
- line, deleted = byteslice!(current_line, 0, @byte_pointer)
- set_current_line(line, 0)
+ @line, deleted = byteslice!(@line, 0, @byte_pointer)
+ @byte_pointer = 0
@kill_ring.append(deleted, true)
+ @cursor_max = calculate_width(@line)
+ @cursor = 0
end
end
alias_method :unix_line_discard, :vi_kill_line_prev
@@ -1913,35 +2649,50 @@ class Reline::LineEditor
# GNU Readline:: +kill-whole-line+ (not bound) Kill all characters on the
# current line, no matter where point is.
private def em_kill_line(key)
- if current_line.size > 0
- @kill_ring.append(current_line.dup, true)
- set_current_line('', 0)
+ if @line.size > 0
+ @kill_ring.append(@line.dup, true)
+ @line.clear
+ @byte_pointer = 0
+ @cursor_max = 0
+ @cursor = 0
end
end
alias_method :kill_whole_line, :em_kill_line
private def em_delete(key)
- if buffer_empty? 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)
+ end
+ Reline::IOGate.move_cursor_column(0)
@eof = true
finish
- elsif @byte_pointer < current_line.bytesize
- splitted_last = current_line.byteslice(@byte_pointer, current_line.bytesize)
+ elsif @byte_pointer < @line.bytesize
+ splitted_last = @line.byteslice(@byte_pointer, @line.bytesize)
mbchar = splitted_last.grapheme_clusters.first
- line, = byteslice!(current_line, @byte_pointer, mbchar.bytesize)
- set_current_line(line)
- elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
- set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor_max -= width
+ @line, = byteslice!(@line, @byte_pointer, mbchar.bytesize)
+ elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1
+ @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ @line += @buffer_of_lines.delete_at(@line_index + 1)
+ @cursor_max = calculate_width(@line)
+ @buffer_of_lines[@line_index] = @line
+ @rerender_all = true
+ @rest_height += 1
end
end
alias_method :delete_char, :em_delete
private def em_delete_or_list(key)
- if current_line.empty? or @byte_pointer < current_line.bytesize
+ if @line.empty? or @byte_pointer < @line.bytesize
em_delete(key)
- elsif !@config.autocompletion # show completed list
+ else # show completed list
result = call_completion_proc
if result.is_a?(Array)
- perform_completion(result, true)
+ complete(result, true)
end
end
end
@@ -1949,135 +2700,162 @@ class Reline::LineEditor
private def em_yank(key)
yanked = @kill_ring.yank
- insert_text(yanked) if yanked
+ if yanked
+ @line = byteinsert(@line, @byte_pointer, yanked)
+ yanked_width = calculate_width(yanked)
+ @cursor += yanked_width
+ @cursor_max += yanked_width
+ @byte_pointer += yanked.bytesize
+ end
end
alias_method :yank, :em_yank
private def em_yank_pop(key)
yanked, prev_yank = @kill_ring.yank_pop
if yanked
- line, = byteslice!(current_line, @byte_pointer - prev_yank.bytesize, prev_yank.bytesize)
- set_current_line(line, @byte_pointer - prev_yank.bytesize)
- insert_text(yanked)
+ prev_yank_width = calculate_width(prev_yank)
+ @cursor -= prev_yank_width
+ @cursor_max -= prev_yank_width
+ @byte_pointer -= prev_yank.bytesize
+ @line, = byteslice!(@line, @byte_pointer, prev_yank.bytesize)
+ @line = byteinsert(@line, @byte_pointer, yanked)
+ yanked_width = calculate_width(yanked)
+ @cursor += yanked_width
+ @cursor_max += yanked_width
+ @byte_pointer += yanked.bytesize
end
end
alias_method :yank_pop, :em_yank_pop
private def ed_clear_screen(key)
- Reline::IOGate.clear_screen
- @screen_size = Reline::IOGate.get_screen_size
- @rendered_screen.base_y = 0
- clear_rendered_screen_cache
+ @cleared = true
end
alias_method :clear_screen, :ed_clear_screen
private def em_next_word(key)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.em_forward_word(@line, @byte_pointer)
@byte_pointer += byte_size
+ @cursor += width
end
end
alias_method :forward_word, :em_next_word
private def ed_prev_word(key)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
+ byte_size, width = Reline::Unicode.em_backward_word(@line, @byte_pointer)
@byte_pointer -= byte_size
+ @cursor -= width
end
end
alias_method :backward_word, :ed_prev_word
private def em_delete_next_word(key)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- line, word = byteslice!(current_line, @byte_pointer, byte_size)
- set_current_line(line)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.em_forward_word(@line, @byte_pointer)
+ @line, word = byteslice!(@line, @byte_pointer, byte_size)
@kill_ring.append(word)
+ @cursor_max -= width
end
end
- alias_method :kill_word, :em_delete_next_word
private def ed_delete_prev_word(key)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
- line, word = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
- set_current_line(line, @byte_pointer - byte_size)
+ byte_size, width = Reline::Unicode.em_backward_word(@line, @byte_pointer)
+ @line, word = byteslice!(@line, @byte_pointer - byte_size, byte_size)
@kill_ring.append(word, true)
+ @byte_pointer -= byte_size
+ @cursor -= width
+ @cursor_max -= width
end
end
- alias_method :backward_kill_word, :ed_delete_prev_word
private def ed_transpose_chars(key)
if @byte_pointer > 0
- if @byte_pointer < current_line.bytesize
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
+ if @cursor_max > @cursor
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor += width
@byte_pointer += byte_size
end
- back1_byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
+ back1_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
if (@byte_pointer - back1_byte_size) > 0
- back2_byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer - back1_byte_size)
+ back2_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer - back1_byte_size)
back2_pointer = @byte_pointer - back1_byte_size - back2_byte_size
- line, back2_mbchar = byteslice!(current_line, back2_pointer, back2_byte_size)
- set_current_line(byteinsert(line, @byte_pointer - back2_byte_size, back2_mbchar))
+ @line, back2_mbchar = byteslice!(@line, back2_pointer, back2_byte_size)
+ @line = byteinsert(@line, @byte_pointer - back2_byte_size, back2_mbchar)
end
end
end
alias_method :transpose_chars, :ed_transpose_chars
private def ed_transpose_words(key)
- left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(current_line, @byte_pointer)
- before = current_line.byteslice(0, left_word_start)
- left_word = current_line.byteslice(left_word_start, middle_start - left_word_start)
- middle = current_line.byteslice(middle_start, right_word_start - middle_start)
- right_word = current_line.byteslice(right_word_start, after_start - right_word_start)
- after = current_line.byteslice(after_start, current_line.bytesize - after_start)
+ left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(@line, @byte_pointer)
+ before = @line.byteslice(0, left_word_start)
+ left_word = @line.byteslice(left_word_start, middle_start - left_word_start)
+ middle = @line.byteslice(middle_start, right_word_start - middle_start)
+ right_word = @line.byteslice(right_word_start, after_start - right_word_start)
+ after = @line.byteslice(after_start, @line.bytesize - after_start)
return if left_word.empty? or right_word.empty?
+ @line = before + right_word + middle + left_word + after
from_head_to_left_word = before + right_word + middle + left_word
- set_current_line(from_head_to_left_word + after, from_head_to_left_word.bytesize)
+ @byte_pointer = from_head_to_left_word.bytesize
+ @cursor = calculate_width(from_head_to_left_word)
end
alias_method :transpose_words, :ed_transpose_words
private def em_capitol_case(key)
- if current_line.bytesize > @byte_pointer
- byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(current_line, @byte_pointer)
- before = current_line.byteslice(0, @byte_pointer)
- after = current_line.byteslice((@byte_pointer + byte_size)..-1)
- set_current_line(before + new_str + after, @byte_pointer + new_str.bytesize)
+ if @line.bytesize > @byte_pointer
+ byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(@line, @byte_pointer)
+ before = @line.byteslice(0, @byte_pointer)
+ after = @line.byteslice((@byte_pointer + byte_size)..-1)
+ @line = before + new_str + after
+ @byte_pointer += new_str.bytesize
+ @cursor += calculate_width(new_str)
end
end
alias_method :capitalize_word, :em_capitol_case
private def em_lower_case(key)
- if current_line.bytesize > @byte_pointer
- byte_size, = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
+ if @line.bytesize > @byte_pointer
+ byte_size, = Reline::Unicode.em_forward_word(@line, @byte_pointer)
+ part = @line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
mbchar =~ /[A-Z]/ ? mbchar.downcase : mbchar
}.join
- rest = current_line.byteslice((@byte_pointer + byte_size)..-1)
- line = current_line.byteslice(0, @byte_pointer) + part
- set_current_line(line + rest, line.bytesize)
+ rest = @line.byteslice((@byte_pointer + byte_size)..-1)
+ @line = @line.byteslice(0, @byte_pointer) + part
+ @byte_pointer = @line.bytesize
+ @cursor = calculate_width(@line)
+ @cursor_max = @cursor + calculate_width(rest)
+ @line += rest
end
end
alias_method :downcase_word, :em_lower_case
private def em_upper_case(key)
- if current_line.bytesize > @byte_pointer
- byte_size, = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
+ if @line.bytesize > @byte_pointer
+ byte_size, = Reline::Unicode.em_forward_word(@line, @byte_pointer)
+ part = @line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
mbchar =~ /[a-z]/ ? mbchar.upcase : mbchar
}.join
- rest = current_line.byteslice((@byte_pointer + byte_size)..-1)
- line = current_line.byteslice(0, @byte_pointer) + part
- set_current_line(line + rest, line.bytesize)
+ rest = @line.byteslice((@byte_pointer + byte_size)..-1)
+ @line = @line.byteslice(0, @byte_pointer) + part
+ @byte_pointer = @line.bytesize
+ @cursor = calculate_width(@line)
+ @cursor_max = @cursor + calculate_width(rest)
+ @line += rest
end
end
alias_method :upcase_word, :em_upper_case
private def em_kill_region(key)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.em_big_backward_word(current_line, @byte_pointer)
- line, deleted = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
- set_current_line(line, @byte_pointer - byte_size)
+ byte_size, width = Reline::Unicode.em_big_backward_word(@line, @byte_pointer)
+ @line, deleted = byteslice!(@line, @byte_pointer - byte_size, byte_size)
+ @byte_pointer -= byte_size
+ @cursor -= width
+ @cursor_max -= width
@kill_ring.append(deleted, true)
end
end
@@ -2105,9 +2883,10 @@ class Reline::LineEditor
alias_method :vi_movement_mode, :vi_command_mode
private def vi_next_word(key, arg: 1)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.vi_forward_word(current_line, @byte_pointer, @drop_terminate_spaces)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.vi_forward_word(@line, @byte_pointer, @drop_terminate_spaces)
@byte_pointer += byte_size
+ @cursor += width
end
arg -= 1
vi_next_word(key, arg: arg) if arg > 0
@@ -2115,32 +2894,38 @@ class Reline::LineEditor
private def vi_prev_word(key, arg: 1)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.vi_backward_word(current_line, @byte_pointer)
+ byte_size, width = Reline::Unicode.vi_backward_word(@line, @byte_pointer)
@byte_pointer -= byte_size
+ @cursor -= width
end
arg -= 1
vi_prev_word(key, arg: arg) if arg > 0
end
private def vi_end_word(key, arg: 1, inclusive: false)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.vi_forward_end_word(current_line, @byte_pointer)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.vi_forward_end_word(@line, @byte_pointer)
@byte_pointer += byte_size
+ @cursor += width
end
arg -= 1
if inclusive and arg.zero?
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
if byte_size > 0
+ c = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(c)
@byte_pointer += byte_size
+ @cursor += width
end
end
vi_end_word(key, arg: arg) if arg > 0
end
private def vi_next_big_word(key, arg: 1)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.vi_big_forward_word(current_line, @byte_pointer)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.vi_big_forward_word(@line, @byte_pointer)
@byte_pointer += byte_size
+ @cursor += width
end
arg -= 1
vi_next_big_word(key, arg: arg) if arg > 0
@@ -2148,39 +2933,50 @@ class Reline::LineEditor
private def vi_prev_big_word(key, arg: 1)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.vi_big_backward_word(current_line, @byte_pointer)
+ byte_size, width = Reline::Unicode.vi_big_backward_word(@line, @byte_pointer)
@byte_pointer -= byte_size
+ @cursor -= width
end
arg -= 1
vi_prev_big_word(key, arg: arg) if arg > 0
end
private def vi_end_big_word(key, arg: 1, inclusive: false)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.vi_big_forward_end_word(current_line, @byte_pointer)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.vi_big_forward_end_word(@line, @byte_pointer)
@byte_pointer += byte_size
+ @cursor += width
end
arg -= 1
if inclusive and arg.zero?
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
if byte_size > 0
+ c = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(c)
@byte_pointer += byte_size
+ @cursor += width
end
end
vi_end_big_word(key, arg: arg) if arg > 0
end
private def vi_delete_prev_char(key)
- if @byte_pointer == 0 and @line_index > 0
+ if @is_multiline and @cursor == 0 and @line_index > 0
+ @buffer_of_lines[@line_index] = @line
+ @cursor = calculate_width(@buffer_of_lines[@line_index - 1])
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
@line_index -= 1
- process_auto_indent cursor_dependent: false
- elsif @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
+ @line = @buffer_of_lines[@line_index]
+ @cursor_max = calculate_width(@line)
+ @rerender_all = true
+ elsif @cursor > 0
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
@byte_pointer -= byte_size
- line, _ = byteslice!(current_line, @byte_pointer, byte_size)
- set_current_line(line)
+ @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
+ @cursor_max -= width
end
end
@@ -2195,84 +2991,78 @@ class Reline::LineEditor
end
private def ed_delete_prev_char(key, arg: 1)
- deleted = +''
+ deleted = ''
arg.times do
- if @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
+ if @cursor > 0
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
@byte_pointer -= byte_size
- line, mbchar = byteslice!(current_line, @byte_pointer, byte_size)
- set_current_line(line)
+ @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
deleted.prepend(mbchar)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
+ @cursor_max -= width
end
end
copy_for_vi(deleted)
end
- private def vi_change_meta(key, arg: nil)
- if @vi_waiting_operator
- set_current_line('', 0) if @vi_waiting_operator == :vi_change_meta_confirm && arg.nil?
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- else
- @drop_terminate_spaces = true
- @vi_waiting_operator = :vi_change_meta_confirm
- @vi_waiting_operator_arg = arg || 1
- end
- end
-
- private def vi_change_meta_confirm(byte_pointer_diff)
- vi_delete_meta_confirm(byte_pointer_diff)
- @config.editing_mode = :vi_insert
- @drop_terminate_spaces = false
- end
-
- private def vi_delete_meta(key, arg: nil)
- if @vi_waiting_operator
- set_current_line('', 0) if @vi_waiting_operator == :vi_delete_meta_confirm && arg.nil?
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- else
- @vi_waiting_operator = :vi_delete_meta_confirm
- @vi_waiting_operator_arg = arg || 1
- end
- end
-
- private def vi_delete_meta_confirm(byte_pointer_diff)
- if byte_pointer_diff > 0
- line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
- elsif byte_pointer_diff < 0
- line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
- else
- return
- end
- copy_for_vi(cut)
- set_current_line(line, @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
+ private def vi_zero(key)
+ @byte_pointer = 0
+ @cursor = 0
+ end
+
+ private def vi_change_meta(key, arg: 1)
+ @drop_terminate_spaces = true
+ @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
+ if byte_pointer_diff > 0
+ @line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff)
+ elsif byte_pointer_diff < 0
+ @line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
+ end
+ copy_for_vi(cut)
+ @cursor += cursor_diff if cursor_diff < 0
+ @cursor_max -= cursor_diff.abs
+ @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
+ @config.editing_mode = :vi_insert
+ @drop_terminate_spaces = false
+ }
+ @waiting_operator_vi_arg = arg
end
- private def vi_yank(key, arg: nil)
- if @vi_waiting_operator
- copy_for_vi(current_line) if @vi_waiting_operator == :vi_yank_confirm && arg.nil?
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- else
- @vi_waiting_operator = :vi_yank_confirm
- @vi_waiting_operator_arg = arg || 1
- end
+ private def vi_delete_meta(key, arg: 1)
+ @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
+ if byte_pointer_diff > 0
+ @line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff)
+ elsif byte_pointer_diff < 0
+ @line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
+ end
+ copy_for_vi(cut)
+ @cursor += cursor_diff if cursor_diff < 0
+ @cursor_max -= cursor_diff.abs
+ @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
+ }
+ @waiting_operator_vi_arg = arg
end
- private def vi_yank_confirm(byte_pointer_diff)
- if byte_pointer_diff > 0
- cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
- elsif byte_pointer_diff < 0
- cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
- else
- return
- end
- copy_for_vi(cut)
+ private def vi_yank(key, arg: 1)
+ @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
+ if byte_pointer_diff > 0
+ cut = @line.byteslice(@byte_pointer, byte_pointer_diff)
+ elsif byte_pointer_diff < 0
+ cut = @line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
+ end
+ copy_for_vi(cut)
+ }
+ @waiting_operator_vi_arg = arg
end
private def vi_list_or_eof(key)
- if buffer_empty?
+ 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)
+ end
+ Reline::IOGate.move_cursor_column(0)
@eof = true
finish
else
@@ -2283,15 +3073,18 @@ class Reline::LineEditor
alias_method :vi_eof_maybe, :vi_list_or_eof
private def ed_delete_next_char(key, arg: 1)
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- unless current_line.empty? || byte_size == 0
- line, mbchar = byteslice!(current_line, @byte_pointer, byte_size)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ unless @line.empty? || byte_size == 0
+ @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
copy_for_vi(mbchar)
- if @byte_pointer > 0 && current_line.bytesize == @byte_pointer + byte_size
- byte_size = Reline::Unicode.get_prev_mbchar_size(line, @byte_pointer)
- set_current_line(line, @byte_pointer - byte_size)
- else
- set_current_line(line, @byte_pointer)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor_max -= width
+ if @cursor > 0 and @cursor >= @cursor_max
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
+ mbchar = @line.byteslice(@byte_pointer - byte_size, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @byte_pointer -= byte_size
+ @cursor -= width
end
end
arg -= 1
@@ -2302,25 +3095,54 @@ class Reline::LineEditor
if Reline::HISTORY.empty?
return
end
- move_history(0, line: :start, cursor: :start)
+ if @history_pointer.nil?
+ @history_pointer = 0
+ @line_backup_in_history = @line
+ @line = Reline::HISTORY[@history_pointer]
+ @cursor_max = calculate_width(@line)
+ @cursor = 0
+ @byte_pointer = 0
+ elsif @history_pointer.zero?
+ return
+ else
+ Reline::HISTORY[@history_pointer] = @line
+ @history_pointer = 0
+ @line = Reline::HISTORY[@history_pointer]
+ @cursor_max = calculate_width(@line)
+ @cursor = 0
+ @byte_pointer = 0
+ end
end
private def vi_histedit(key)
path = Tempfile.open { |fp|
- fp.write whole_lines.join("\n")
+ if @is_multiline
+ fp.write whole_lines.join("\n")
+ else
+ fp.write @line
+ end
fp.path
}
system("#{ENV['EDITOR']} #{path}")
- @buffer_of_lines = File.read(path).split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = 0
+ if @is_multiline
+ @buffer_of_lines = File.read(path).split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = 0
+ @line = @buffer_of_lines[@line_index]
+ @rerender_all = true
+ else
+ @line = File.read(path)
+ end
finish
end
private def vi_paste_prev(key, arg: 1)
if @vi_clipboard.size > 0
+ @line = byteinsert(@line, @byte_pointer, @vi_clipboard)
+ @cursor_max += calculate_width(@vi_clipboard)
cursor_point = @vi_clipboard.grapheme_clusters[0..-2].join
- set_current_line(byteinsert(current_line, @byte_pointer, @vi_clipboard), @byte_pointer + cursor_point.bytesize)
+ @cursor += calculate_width(cursor_point)
+ @byte_pointer += cursor_point.bytesize
end
arg -= 1
vi_paste_prev(key, arg: arg) if arg > 0
@@ -2328,9 +3150,11 @@ class Reline::LineEditor
private def vi_paste_next(key, arg: 1)
if @vi_clipboard.size > 0
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- line = byteinsert(current_line, @byte_pointer + byte_size, @vi_clipboard)
- set_current_line(line, @byte_pointer + @vi_clipboard.bytesize)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ @line = byteinsert(@line, @byte_pointer + byte_size, @vi_clipboard)
+ @cursor_max += calculate_width(@vi_clipboard)
+ @cursor += calculate_width(@vi_clipboard)
+ @byte_pointer += @vi_clipboard.bytesize
end
arg -= 1
vi_paste_next(key, arg: arg) if arg > 0
@@ -2354,33 +3178,43 @@ class Reline::LineEditor
end
private def vi_to_column(key, arg: 0)
- # Implementing behavior of vi, not Readline's vi-mode.
- @byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |(total_byte_size, total_width), gc|
+ @byte_pointer, @cursor = @line.grapheme_clusters.inject([0, 0]) { |total, gc|
+ # total has [byte_size, cursor]
mbchar_width = Reline::Unicode.get_mbchar_width(gc)
- break [total_byte_size, total_width] if (total_width + mbchar_width) >= arg
- [total_byte_size + gc.bytesize, total_width + mbchar_width]
+ if (total.last + mbchar_width) >= arg
+ break total
+ elsif (total.last + mbchar_width) >= @cursor_max
+ break total
+ else
+ total = [total.first + gc.bytesize, total.last + mbchar_width]
+ total
+ end
}
end
private def vi_replace_char(key, arg: 1)
@waiting_proc = ->(k) {
if arg == 1
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- before = current_line.byteslice(0, @byte_pointer)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ before = @line.byteslice(0, @byte_pointer)
remaining_point = @byte_pointer + byte_size
- after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
- set_current_line(before + k.chr + after)
+ after = @line.byteslice(remaining_point, @line.bytesize - remaining_point)
+ @line = before + k.chr + after
+ @cursor_max = calculate_width(@line)
@waiting_proc = nil
elsif arg > 1
byte_size = 0
arg.times do
- byte_size += Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer + byte_size)
+ byte_size += Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer + byte_size)
end
- before = current_line.byteslice(0, @byte_pointer)
+ before = @line.byteslice(0, @byte_pointer)
remaining_point = @byte_pointer + byte_size
- after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
+ after = @line.byteslice(remaining_point, @line.bytesize - remaining_point)
replaced = k.chr * arg
- set_current_line(before + replaced + after, @byte_pointer + replaced.bytesize)
+ @line = before + replaced + after
+ @byte_pointer += replaced.bytesize
+ @cursor += calculate_width(replaced)
+ @cursor_max = calculate_width(@line)
@waiting_proc = nil
end
}
@@ -2403,7 +3237,7 @@ class Reline::LineEditor
prev_total = nil
total = nil
found = false
- current_line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
+ @line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
# total has [byte_size, cursor]
unless total
# skip cursor point
@@ -2423,16 +3257,21 @@ class Reline::LineEditor
end
end
if not need_prev_char and found and total
- byte_size, _ = total
+ byte_size, width = total
@byte_pointer += byte_size
+ @cursor += width
elsif need_prev_char and found and prev_total
- byte_size, _ = prev_total
+ byte_size, width = prev_total
@byte_pointer += byte_size
+ @cursor += width
end
if inclusive
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
if byte_size > 0
+ c = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(c)
@byte_pointer += byte_size
+ @cursor += width
end
end
@waiting_proc = nil
@@ -2455,7 +3294,7 @@ class Reline::LineEditor
prev_total = nil
total = nil
found = false
- current_line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
+ @line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
# total has [byte_size, cursor]
unless total
# skip cursor point
@@ -2475,19 +3314,26 @@ class Reline::LineEditor
end
end
if not need_next_char and found and total
- byte_size, _ = total
+ byte_size, width = total
@byte_pointer -= byte_size
+ @cursor -= width
elsif need_next_char and found and prev_total
- byte_size, _ = prev_total
+ byte_size, width = prev_total
@byte_pointer -= byte_size
+ @cursor -= width
end
@waiting_proc = nil
end
private def vi_join_lines(key, arg: 1)
- if @buffer_of_lines.size > @line_index + 1
- next_line = @buffer_of_lines.delete_at(@line_index + 1).lstrip
- set_current_line(current_line + ' ' + next_line, current_line.bytesize)
+ if @is_multiline and @buffer_of_lines.size > @line_index + 1
+ @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ @line += ' ' + @buffer_of_lines.delete_at(@line_index + 1).lstrip
+ @cursor_max = calculate_width(@line)
+ @buffer_of_lines[@line_index] = @line
+ @rerender_all = true
+ @rest_height += 1
end
arg -= 1
vi_join_lines(key, arg: arg) if arg > 0
@@ -2501,48 +3347,11 @@ class Reline::LineEditor
private def em_exchange_mark(key)
return unless @mark_pointer
new_pointer = [@byte_pointer, @line_index]
+ @previous_line_index = @line_index
@byte_pointer, @line_index = @mark_pointer
+ @cursor = calculate_width(@line.byteslice(0, @byte_pointer))
+ @cursor_max = calculate_width(@line)
@mark_pointer = new_pointer
end
alias_method :exchange_point_and_mark, :em_exchange_mark
-
- private def emacs_editing_mode(key)
- @config.editing_mode = :emacs
- end
-
- private def vi_editing_mode(key)
- @config.editing_mode = :vi_insert
- end
-
- private def undo(_key)
- @undoing = true
-
- return if @input_lines_position <= 0
-
- @input_lines_position -= 1
- target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
- set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
- end
-
- private def redo(_key)
- @undoing = true
-
- return if @input_lines_position >= @input_lines.size - 1
-
- @input_lines_position += 1
- target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
- set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
- end
-
- private def prev_action_state_value(type)
- @prev_action_state[0] == type ? @prev_action_state[1] : nil
- end
-
- private def set_next_action_state(type, value)
- @next_action_state = [type, value]
- end
-
- private def re_read_init_file(_key)
- @config.reload
- end
end
diff --git a/lib/reline/reline.gemspec b/lib/reline/reline.gemspec
index dfaf966728..7bf1f8758b 100644
--- a/lib/reline/reline.gemspec
+++ b/lib/reline/reline.gemspec
@@ -18,11 +18,6 @@ Gem::Specification.new do |spec|
spec.files = Dir['BSDL', 'COPYING', 'README.md', 'license_of_rb-readline', 'lib/**/*']
spec.require_paths = ['lib']
- spec.metadata = {
- "bug_tracker_uri" => "https://github.com/ruby/reline/issues",
- "changelog_uri" => "https://github.com/ruby/reline/releases",
- "source_code_uri" => "https://github.com/ruby/reline"
- }
spec.required_ruby_version = Gem::Requirement.new('>= 2.6')
diff --git a/lib/reline/terminfo.rb b/lib/reline/terminfo.rb
index c2b1f681b4..f53642b919 100644
--- a/lib/reline/terminfo.rb
+++ b/lib/reline/terminfo.rb
@@ -1,7 +1,4 @@
begin
- # Ignore warning `Add fiddle to your Gemfile or gemspec` in Ruby 3.4.
- # terminfo.rb and ansi.rb supports fiddle unavailable environment.
- verbose, $VERBOSE = $VERBOSE, nil
require 'fiddle'
require 'fiddle/import'
rescue LoadError
@@ -10,8 +7,6 @@ rescue LoadError
false
end
end
-ensure
- $VERBOSE = verbose
end
module Reline::Terminfo
@@ -36,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
@@ -83,13 +92,25 @@ module Reline::Terminfo
end
def self.setupterm(term, fildes)
- errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE)
+ errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
ret = @setupterm.(term, fildes, errret_int)
+ errret = errret_int[0, Fiddle::SIZEOF_INT].unpack1('i')
case ret
when 0 # OK
- @term_supported = true
+ 0
when -1 # ERR
- @term_supported = false
+ case errret
+ when 1
+ raise TerminfoError.new('The terminal is hardcopy, cannot be used for curses applications.')
+ when 0
+ raise TerminfoError.new('The terminal could not be found, or that it is a generic type, having too little information for curses applications to run.')
+ when -1
+ raise TerminfoError.new('The terminfo database could not be found.')
+ else # unknown
+ -1
+ end
+ else # unknown
+ -2
end
end
@@ -141,14 +162,9 @@ module Reline::Terminfo
num
end
- # NOTE: This means Fiddle and curses are enabled.
def self.enabled?
true
end
-
- def self.term_supported?
- @term_supported
- end
end if Reline::Terminfo.curses_dl
module Reline::Terminfo
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
index ef239d5e9e..6000c9f82a 100644
--- a/lib/reline/unicode.rb
+++ b/lib/reline/unicode.rb
@@ -38,44 +38,92 @@ 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|
- case gr
- when -"\n"
- gr
- when -"\t"
- -' '
+ escaped = EscapedPairs[gr.ord]
+ if escaped && gr != -"\n" && gr != -"\t"
+ escaped
else
- EscapedPairs[gr.ord] || gr
+ gr
end
}.join
end
require 'reline/unicode/east_asian_width'
+ HalfwidthDakutenHandakuten = /[\u{FF9E}\u{FF9F}]/
+
+ MBCharWidthRE = /
+ (?<width_2_1>
+ [#{ EscapedChars.map {|c| "\\x%02x" % c.ord }.join }] (?# ^ + char, such as ^M, ^H, ^[, ...)
+ )
+ | (?<width_3>^\u{2E3B}) (?# THREE-EM DASH)
+ | (?<width_0>^\p{M})
+ | (?<width_2_2>
+ #{ EastAsianWidth::TYPE_F }
+ | #{ EastAsianWidth::TYPE_W }
+ )
+ | (?<width_1>
+ #{ EastAsianWidth::TYPE_H }
+ | #{ EastAsianWidth::TYPE_NA }
+ | #{ EastAsianWidth::TYPE_N }
+ )(?!#{ HalfwidthDakutenHandakuten })
+ | (?<width_2_3>
+ (?: #{ EastAsianWidth::TYPE_H }
+ | #{ EastAsianWidth::TYPE_NA }
+ | #{ EastAsianWidth::TYPE_N })
+ #{ HalfwidthDakutenHandakuten }
+ )
+ | (?<ambiguous_width>
+ #{EastAsianWidth::TYPE_A}
+ )
+ /x
+
def self.get_mbchar_width(mbchar)
ord = mbchar.ord
- if ord <= 0x1F # in EscapedPairs
+ if (0x00 <= ord and ord <= 0x1F) # in EscapedPairs
return 2
- elsif ord <= 0x7E # printable ASCII chars
+ elsif (0x20 <= ord and ord <= 0x7E) # printable ASCII chars
return 1
end
- utf8_mbchar = mbchar.encode(Encoding::UTF_8)
- ord = utf8_mbchar.ord
- chunk_index = EastAsianWidth::CHUNK_LAST.bsearch_index { |o| ord <= o }
- size = EastAsianWidth::CHUNK_WIDTH[chunk_index]
- if size == -1
- Reline.ambiguous_width
- elsif size == 1 && utf8_mbchar.size >= 2
- second_char_ord = utf8_mbchar[1].ord
- # Halfwidth Dakuten Handakuten
- # Only these two character has Letter Modifier category and can be combined in a single grapheme cluster
- (second_char_ord == 0xFF9E || second_char_ord == 0xFF9F) ? 2 : 1
+ m = mbchar.encode(Encoding::UTF_8).match(MBCharWidthRE)
+ case
+ when m.nil? then 1 # TODO should be U+FFFD � REPLACEMENT CHARACTER
+ when m[:width_2_1], m[:width_2_2], m[:width_2_3] then 2
+ when m[:width_3] then 3
+ when m[:width_0] then 0
+ when m[:width_1] then 1
+ when m[:ambiguous_width] then Reline.ambiguous_width
else
- size
+ nil
end
end
@@ -84,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
@@ -105,40 +154,30 @@ class Reline::Unicode
end
end
- def self.split_by_width(str, max_width, encoding = str.encoding, offset: 0)
+ def self.split_by_width(str, max_width, encoding = str.encoding)
lines = [String.new(encoding: encoding)]
height = 1
- width = offset
+ 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
- unless in_zero_width
- if csi == -"\e[m" || csi == -"\e[0m"
- seq.clear
- else
- seq << csi
- end
- end
- 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
@@ -155,79 +194,34 @@ 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)
- take_mbchar_range(str, start_col, max_width).first
- end
-
- def self.take_mbchar_range(str, start_col, width, cover_begin: false, cover_end: false, padding: false)
- chunk = String.new(encoding: str.encoding)
-
- end_col = start_col + width
+ 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
- chunk_start_col = nil
- chunk_end_col = nil
- has_csi = 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
- chunk << NON_PRINTING_START
- when non_printing_end
+ when gc[NON_PRINTING_END_INDEX]
in_zero_width = false
- chunk << NON_PRINTING_END
- when csi
- has_csi = true
- 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
- next
- end
-
- mbchar_width = get_mbchar_width(gc)
- prev_width = total_width
- total_width += mbchar_width
-
- if (cover_begin || padding ? total_width <= start_col : prev_width < start_col)
- # Current character haven't reached start_col yet
- next
- elsif padding && !cover_begin && prev_width < start_col && start_col < total_width
- # Add preceding padding. This padding might have background color.
- chunk << ' '
- chunk_start_col ||= start_col
- chunk_end_col = total_width
- next
- elsif (cover_end ? prev_width < end_col : total_width <= end_col)
- # Current character is in the range
- chunk << gc
- chunk_start_col ||= prev_width
- chunk_end_col = total_width
- break if total_width >= end_col
else
- # Current character exceeds end_col
- if padding && end_col < total_width
- # Add succeeding padding. This padding might have background color.
- chunk << ' '
- chunk_start_col ||= prev_width
- chunk_end_col = end_col
- end
- break
+ mbchar_width = get_mbchar_width(gc)
+ total_width += mbchar_width
+ break if (start_col + max_width) < total_width
+ chunk << gc if start_col < total_width
end
end
end
- chunk_start_col ||= start_col
- chunk_end_col ||= start_col
- if padding && chunk_end_col < end_col
- # Append padding. This padding should not include background color.
- chunk << "\e[0m" if has_csi
- chunk << ' ' * (end_col - chunk_end_col)
- chunk_end_col = end_col
- end
- [chunk, chunk_start_col, chunk_end_col - chunk_start_col]
+ chunk
end
def self.get_next_mbchar_size(line, byte_pointer)
diff --git a/lib/reline/unicode/east_asian_width.rb b/lib/reline/unicode/east_asian_width.rb
index 106ca4881a..89bc9d9435 100644
--- a/lib/reline/unicode/east_asian_width.rb
+++ b/lib/reline/unicode/east_asian_width.rb
@@ -1,1267 +1,1164 @@
class Reline::Unicode::EastAsianWidth
# This is based on EastAsianWidth.txt
- # UNICODE_VERSION = '15.1.0'
+ # EastAsianWidth.txt
- CHUNK_LAST, CHUNK_WIDTH = [
- [0x1f, 2],
- [0x7e, 1],
- [0x7f, 2],
- [0xa0, 1],
- [0xa1, -1],
- [0xa3, 1],
- [0xa4, -1],
- [0xa6, 1],
- [0xa8, -1],
- [0xa9, 1],
- [0xaa, -1],
- [0xac, 1],
- [0xae, -1],
- [0xaf, 1],
- [0xb4, -1],
- [0xb5, 1],
- [0xba, -1],
- [0xbb, 1],
- [0xbf, -1],
- [0xc5, 1],
- [0xc6, -1],
- [0xcf, 1],
- [0xd0, -1],
- [0xd6, 1],
- [0xd8, -1],
- [0xdd, 1],
- [0xe1, -1],
- [0xe5, 1],
- [0xe6, -1],
- [0xe7, 1],
- [0xea, -1],
- [0xeb, 1],
- [0xed, -1],
- [0xef, 1],
- [0xf0, -1],
- [0xf1, 1],
- [0xf3, -1],
- [0xf6, 1],
- [0xfa, -1],
- [0xfb, 1],
- [0xfc, -1],
- [0xfd, 1],
- [0xfe, -1],
- [0x100, 1],
- [0x101, -1],
- [0x110, 1],
- [0x111, -1],
- [0x112, 1],
- [0x113, -1],
- [0x11a, 1],
- [0x11b, -1],
- [0x125, 1],
- [0x127, -1],
- [0x12a, 1],
- [0x12b, -1],
- [0x130, 1],
- [0x133, -1],
- [0x137, 1],
- [0x138, -1],
- [0x13e, 1],
- [0x142, -1],
- [0x143, 1],
- [0x144, -1],
- [0x147, 1],
- [0x14b, -1],
- [0x14c, 1],
- [0x14d, -1],
- [0x151, 1],
- [0x153, -1],
- [0x165, 1],
- [0x167, -1],
- [0x16a, 1],
- [0x16b, -1],
- [0x1cd, 1],
- [0x1ce, -1],
- [0x1cf, 1],
- [0x1d0, -1],
- [0x1d1, 1],
- [0x1d2, -1],
- [0x1d3, 1],
- [0x1d4, -1],
- [0x1d5, 1],
- [0x1d6, -1],
- [0x1d7, 1],
- [0x1d8, -1],
- [0x1d9, 1],
- [0x1da, -1],
- [0x1db, 1],
- [0x1dc, -1],
- [0x250, 1],
- [0x251, -1],
- [0x260, 1],
- [0x261, -1],
- [0x2c3, 1],
- [0x2c4, -1],
- [0x2c6, 1],
- [0x2c7, -1],
- [0x2c8, 1],
- [0x2cb, -1],
- [0x2cc, 1],
- [0x2cd, -1],
- [0x2cf, 1],
- [0x2d0, -1],
- [0x2d7, 1],
- [0x2db, -1],
- [0x2dc, 1],
- [0x2dd, -1],
- [0x2de, 1],
- [0x2df, -1],
- [0x2ff, 1],
- [0x36f, 0],
- [0x390, 1],
- [0x3a1, -1],
- [0x3a2, 1],
- [0x3a9, -1],
- [0x3b0, 1],
- [0x3c1, -1],
- [0x3c2, 1],
- [0x3c9, -1],
- [0x400, 1],
- [0x401, -1],
- [0x40f, 1],
- [0x44f, -1],
- [0x450, 1],
- [0x451, -1],
- [0x482, 1],
- [0x487, 0],
- [0x590, 1],
- [0x5bd, 0],
- [0x5be, 1],
- [0x5bf, 0],
- [0x5c0, 1],
- [0x5c2, 0],
- [0x5c3, 1],
- [0x5c5, 0],
- [0x5c6, 1],
- [0x5c7, 0],
- [0x60f, 1],
- [0x61a, 0],
- [0x64a, 1],
- [0x65f, 0],
- [0x66f, 1],
- [0x670, 0],
- [0x6d5, 1],
- [0x6dc, 0],
- [0x6de, 1],
- [0x6e4, 0],
- [0x6e6, 1],
- [0x6e8, 0],
- [0x6e9, 1],
- [0x6ed, 0],
- [0x710, 1],
- [0x711, 0],
- [0x72f, 1],
- [0x74a, 0],
- [0x7a5, 1],
- [0x7b0, 0],
- [0x7ea, 1],
- [0x7f3, 0],
- [0x7fc, 1],
- [0x7fd, 0],
- [0x815, 1],
- [0x819, 0],
- [0x81a, 1],
- [0x823, 0],
- [0x824, 1],
- [0x827, 0],
- [0x828, 1],
- [0x82d, 0],
- [0x858, 1],
- [0x85b, 0],
- [0x897, 1],
- [0x89f, 0],
- [0x8c9, 1],
- [0x8e1, 0],
- [0x8e2, 1],
- [0x902, 0],
- [0x939, 1],
- [0x93a, 0],
- [0x93b, 1],
- [0x93c, 0],
- [0x940, 1],
- [0x948, 0],
- [0x94c, 1],
- [0x94d, 0],
- [0x950, 1],
- [0x957, 0],
- [0x961, 1],
- [0x963, 0],
- [0x980, 1],
- [0x981, 0],
- [0x9bb, 1],
- [0x9bc, 0],
- [0x9c0, 1],
- [0x9c4, 0],
- [0x9cc, 1],
- [0x9cd, 0],
- [0x9e1, 1],
- [0x9e3, 0],
- [0x9fd, 1],
- [0x9fe, 0],
- [0xa00, 1],
- [0xa02, 0],
- [0xa3b, 1],
- [0xa3c, 0],
- [0xa40, 1],
- [0xa42, 0],
- [0xa46, 1],
- [0xa48, 0],
- [0xa4a, 1],
- [0xa4d, 0],
- [0xa50, 1],
- [0xa51, 0],
- [0xa6f, 1],
- [0xa71, 0],
- [0xa74, 1],
- [0xa75, 0],
- [0xa80, 1],
- [0xa82, 0],
- [0xabb, 1],
- [0xabc, 0],
- [0xac0, 1],
- [0xac5, 0],
- [0xac6, 1],
- [0xac8, 0],
- [0xacc, 1],
- [0xacd, 0],
- [0xae1, 1],
- [0xae3, 0],
- [0xaf9, 1],
- [0xaff, 0],
- [0xb00, 1],
- [0xb01, 0],
- [0xb3b, 1],
- [0xb3c, 0],
- [0xb3e, 1],
- [0xb3f, 0],
- [0xb40, 1],
- [0xb44, 0],
- [0xb4c, 1],
- [0xb4d, 0],
- [0xb54, 1],
- [0xb56, 0],
- [0xb61, 1],
- [0xb63, 0],
- [0xb81, 1],
- [0xb82, 0],
- [0xbbf, 1],
- [0xbc0, 0],
- [0xbcc, 1],
- [0xbcd, 0],
- [0xbff, 1],
- [0xc00, 0],
- [0xc03, 1],
- [0xc04, 0],
- [0xc3b, 1],
- [0xc3c, 0],
- [0xc3d, 1],
- [0xc40, 0],
- [0xc45, 1],
- [0xc48, 0],
- [0xc49, 1],
- [0xc4d, 0],
- [0xc54, 1],
- [0xc56, 0],
- [0xc61, 1],
- [0xc63, 0],
- [0xc80, 1],
- [0xc81, 0],
- [0xcbb, 1],
- [0xcbc, 0],
- [0xcbe, 1],
- [0xcbf, 0],
- [0xcc5, 1],
- [0xcc6, 0],
- [0xccb, 1],
- [0xccd, 0],
- [0xce1, 1],
- [0xce3, 0],
- [0xcff, 1],
- [0xd01, 0],
- [0xd3a, 1],
- [0xd3c, 0],
- [0xd40, 1],
- [0xd44, 0],
- [0xd4c, 1],
- [0xd4d, 0],
- [0xd61, 1],
- [0xd63, 0],
- [0xd80, 1],
- [0xd81, 0],
- [0xdc9, 1],
- [0xdca, 0],
- [0xdd1, 1],
- [0xdd4, 0],
- [0xdd5, 1],
- [0xdd6, 0],
- [0xe30, 1],
- [0xe31, 0],
- [0xe33, 1],
- [0xe3a, 0],
- [0xe46, 1],
- [0xe4e, 0],
- [0xeb0, 1],
- [0xeb1, 0],
- [0xeb3, 1],
- [0xebc, 0],
- [0xec7, 1],
- [0xece, 0],
- [0xf17, 1],
- [0xf19, 0],
- [0xf34, 1],
- [0xf35, 0],
- [0xf36, 1],
- [0xf37, 0],
- [0xf38, 1],
- [0xf39, 0],
- [0xf70, 1],
- [0xf7e, 0],
- [0xf7f, 1],
- [0xf84, 0],
- [0xf85, 1],
- [0xf87, 0],
- [0xf8c, 1],
- [0xf97, 0],
- [0xf98, 1],
- [0xfbc, 0],
- [0xfc5, 1],
- [0xfc6, 0],
- [0x102c, 1],
- [0x1030, 0],
- [0x1031, 1],
- [0x1037, 0],
- [0x1038, 1],
- [0x103a, 0],
- [0x103c, 1],
- [0x103e, 0],
- [0x1057, 1],
- [0x1059, 0],
- [0x105d, 1],
- [0x1060, 0],
- [0x1070, 1],
- [0x1074, 0],
- [0x1081, 1],
- [0x1082, 0],
- [0x1084, 1],
- [0x1086, 0],
- [0x108c, 1],
- [0x108d, 0],
- [0x109c, 1],
- [0x109d, 0],
- [0x10ff, 1],
- [0x115f, 2],
- [0x135c, 1],
- [0x135f, 0],
- [0x1711, 1],
- [0x1714, 0],
- [0x1731, 1],
- [0x1733, 0],
- [0x1751, 1],
- [0x1753, 0],
- [0x1771, 1],
- [0x1773, 0],
- [0x17b3, 1],
- [0x17b5, 0],
- [0x17b6, 1],
- [0x17bd, 0],
- [0x17c5, 1],
- [0x17c6, 0],
- [0x17c8, 1],
- [0x17d3, 0],
- [0x17dc, 1],
- [0x17dd, 0],
- [0x180a, 1],
- [0x180d, 0],
- [0x180e, 1],
- [0x180f, 0],
- [0x1884, 1],
- [0x1886, 0],
- [0x18a8, 1],
- [0x18a9, 0],
- [0x191f, 1],
- [0x1922, 0],
- [0x1926, 1],
- [0x1928, 0],
- [0x1931, 1],
- [0x1932, 0],
- [0x1938, 1],
- [0x193b, 0],
- [0x1a16, 1],
- [0x1a18, 0],
- [0x1a1a, 1],
- [0x1a1b, 0],
- [0x1a55, 1],
- [0x1a56, 0],
- [0x1a57, 1],
- [0x1a5e, 0],
- [0x1a5f, 1],
- [0x1a60, 0],
- [0x1a61, 1],
- [0x1a62, 0],
- [0x1a64, 1],
- [0x1a6c, 0],
- [0x1a72, 1],
- [0x1a7c, 0],
- [0x1a7e, 1],
- [0x1a7f, 0],
- [0x1aaf, 1],
- [0x1abd, 0],
- [0x1abe, 1],
- [0x1ace, 0],
- [0x1aff, 1],
- [0x1b03, 0],
- [0x1b33, 1],
- [0x1b34, 0],
- [0x1b35, 1],
- [0x1b3a, 0],
- [0x1b3b, 1],
- [0x1b3c, 0],
- [0x1b41, 1],
- [0x1b42, 0],
- [0x1b6a, 1],
- [0x1b73, 0],
- [0x1b7f, 1],
- [0x1b81, 0],
- [0x1ba1, 1],
- [0x1ba5, 0],
- [0x1ba7, 1],
- [0x1ba9, 0],
- [0x1baa, 1],
- [0x1bad, 0],
- [0x1be5, 1],
- [0x1be6, 0],
- [0x1be7, 1],
- [0x1be9, 0],
- [0x1bec, 1],
- [0x1bed, 0],
- [0x1bee, 1],
- [0x1bf1, 0],
- [0x1c2b, 1],
- [0x1c33, 0],
- [0x1c35, 1],
- [0x1c37, 0],
- [0x1ccf, 1],
- [0x1cd2, 0],
- [0x1cd3, 1],
- [0x1ce0, 0],
- [0x1ce1, 1],
- [0x1ce8, 0],
- [0x1cec, 1],
- [0x1ced, 0],
- [0x1cf3, 1],
- [0x1cf4, 0],
- [0x1cf7, 1],
- [0x1cf9, 0],
- [0x1dbf, 1],
- [0x1dff, 0],
- [0x200f, 1],
- [0x2010, -1],
- [0x2012, 1],
- [0x2016, -1],
- [0x2017, 1],
- [0x2019, -1],
- [0x201b, 1],
- [0x201d, -1],
- [0x201f, 1],
- [0x2022, -1],
- [0x2023, 1],
- [0x2027, -1],
- [0x202f, 1],
- [0x2030, -1],
- [0x2031, 1],
- [0x2033, -1],
- [0x2034, 1],
- [0x2035, -1],
- [0x203a, 1],
- [0x203b, -1],
- [0x203d, 1],
- [0x203e, -1],
- [0x2073, 1],
- [0x2074, -1],
- [0x207e, 1],
- [0x207f, -1],
- [0x2080, 1],
- [0x2084, -1],
- [0x20ab, 1],
- [0x20ac, -1],
- [0x20cf, 1],
- [0x20dc, 0],
- [0x20e0, 1],
- [0x20e1, 0],
- [0x20e4, 1],
- [0x20f0, 0],
- [0x2102, 1],
- [0x2103, -1],
- [0x2104, 1],
- [0x2105, -1],
- [0x2108, 1],
- [0x2109, -1],
- [0x2112, 1],
- [0x2113, -1],
- [0x2115, 1],
- [0x2116, -1],
- [0x2120, 1],
- [0x2122, -1],
- [0x2125, 1],
- [0x2126, -1],
- [0x212a, 1],
- [0x212b, -1],
- [0x2152, 1],
- [0x2154, -1],
- [0x215a, 1],
- [0x215e, -1],
- [0x215f, 1],
- [0x216b, -1],
- [0x216f, 1],
- [0x2179, -1],
- [0x2188, 1],
- [0x2189, -1],
- [0x218f, 1],
- [0x2199, -1],
- [0x21b7, 1],
- [0x21b9, -1],
- [0x21d1, 1],
- [0x21d2, -1],
- [0x21d3, 1],
- [0x21d4, -1],
- [0x21e6, 1],
- [0x21e7, -1],
- [0x21ff, 1],
- [0x2200, -1],
- [0x2201, 1],
- [0x2203, -1],
- [0x2206, 1],
- [0x2208, -1],
- [0x220a, 1],
- [0x220b, -1],
- [0x220e, 1],
- [0x220f, -1],
- [0x2210, 1],
- [0x2211, -1],
- [0x2214, 1],
- [0x2215, -1],
- [0x2219, 1],
- [0x221a, -1],
- [0x221c, 1],
- [0x2220, -1],
- [0x2222, 1],
- [0x2223, -1],
- [0x2224, 1],
- [0x2225, -1],
- [0x2226, 1],
- [0x222c, -1],
- [0x222d, 1],
- [0x222e, -1],
- [0x2233, 1],
- [0x2237, -1],
- [0x223b, 1],
- [0x223d, -1],
- [0x2247, 1],
- [0x2248, -1],
- [0x224b, 1],
- [0x224c, -1],
- [0x2251, 1],
- [0x2252, -1],
- [0x225f, 1],
- [0x2261, -1],
- [0x2263, 1],
- [0x2267, -1],
- [0x2269, 1],
- [0x226b, -1],
- [0x226d, 1],
- [0x226f, -1],
- [0x2281, 1],
- [0x2283, -1],
- [0x2285, 1],
- [0x2287, -1],
- [0x2294, 1],
- [0x2295, -1],
- [0x2298, 1],
- [0x2299, -1],
- [0x22a4, 1],
- [0x22a5, -1],
- [0x22be, 1],
- [0x22bf, -1],
- [0x2311, 1],
- [0x2312, -1],
- [0x2319, 1],
- [0x231b, 2],
- [0x2328, 1],
- [0x232a, 2],
- [0x23e8, 1],
- [0x23ec, 2],
- [0x23ef, 1],
- [0x23f0, 2],
- [0x23f2, 1],
- [0x23f3, 2],
- [0x245f, 1],
- [0x24e9, -1],
- [0x24ea, 1],
- [0x254b, -1],
- [0x254f, 1],
- [0x2573, -1],
- [0x257f, 1],
- [0x258f, -1],
- [0x2591, 1],
- [0x2595, -1],
- [0x259f, 1],
- [0x25a1, -1],
- [0x25a2, 1],
- [0x25a9, -1],
- [0x25b1, 1],
- [0x25b3, -1],
- [0x25b5, 1],
- [0x25b7, -1],
- [0x25bb, 1],
- [0x25bd, -1],
- [0x25bf, 1],
- [0x25c1, -1],
- [0x25c5, 1],
- [0x25c8, -1],
- [0x25ca, 1],
- [0x25cb, -1],
- [0x25cd, 1],
- [0x25d1, -1],
- [0x25e1, 1],
- [0x25e5, -1],
- [0x25ee, 1],
- [0x25ef, -1],
- [0x25fc, 1],
- [0x25fe, 2],
- [0x2604, 1],
- [0x2606, -1],
- [0x2608, 1],
- [0x2609, -1],
- [0x260d, 1],
- [0x260f, -1],
- [0x2613, 1],
- [0x2615, 2],
- [0x261b, 1],
- [0x261c, -1],
- [0x261d, 1],
- [0x261e, -1],
- [0x263f, 1],
- [0x2640, -1],
- [0x2641, 1],
- [0x2642, -1],
- [0x2647, 1],
- [0x2653, 2],
- [0x265f, 1],
- [0x2661, -1],
- [0x2662, 1],
- [0x2665, -1],
- [0x2666, 1],
- [0x266a, -1],
- [0x266b, 1],
- [0x266d, -1],
- [0x266e, 1],
- [0x266f, -1],
- [0x267e, 1],
- [0x267f, 2],
- [0x2692, 1],
- [0x2693, 2],
- [0x269d, 1],
- [0x269f, -1],
- [0x26a0, 1],
- [0x26a1, 2],
- [0x26a9, 1],
- [0x26ab, 2],
- [0x26bc, 1],
- [0x26be, 2],
- [0x26bf, -1],
- [0x26c3, 1],
- [0x26c5, 2],
- [0x26cd, -1],
- [0x26ce, 2],
- [0x26d3, -1],
- [0x26d4, 2],
- [0x26e1, -1],
- [0x26e2, 1],
- [0x26e3, -1],
- [0x26e7, 1],
- [0x26e9, -1],
- [0x26ea, 2],
- [0x26f1, -1],
- [0x26f3, 2],
- [0x26f4, -1],
- [0x26f5, 2],
- [0x26f9, -1],
- [0x26fa, 2],
- [0x26fc, -1],
- [0x26fd, 2],
- [0x26ff, -1],
- [0x2704, 1],
- [0x2705, 2],
- [0x2709, 1],
- [0x270b, 2],
- [0x2727, 1],
- [0x2728, 2],
- [0x273c, 1],
- [0x273d, -1],
- [0x274b, 1],
- [0x274c, 2],
- [0x274d, 1],
- [0x274e, 2],
- [0x2752, 1],
- [0x2755, 2],
- [0x2756, 1],
- [0x2757, 2],
- [0x2775, 1],
- [0x277f, -1],
- [0x2794, 1],
- [0x2797, 2],
- [0x27af, 1],
- [0x27b0, 2],
- [0x27be, 1],
- [0x27bf, 2],
- [0x2b1a, 1],
- [0x2b1c, 2],
- [0x2b4f, 1],
- [0x2b50, 2],
- [0x2b54, 1],
- [0x2b55, 2],
- [0x2b59, -1],
- [0x2cee, 1],
- [0x2cf1, 0],
- [0x2d7e, 1],
- [0x2d7f, 0],
- [0x2ddf, 1],
- [0x2dff, 0],
- [0x2e7f, 1],
- [0x2e99, 2],
- [0x2e9a, 1],
- [0x2ef3, 2],
- [0x2eff, 1],
- [0x2fd5, 2],
- [0x2fef, 1],
- [0x3029, 2],
- [0x302d, 0],
- [0x303e, 2],
- [0x3040, 1],
- [0x3096, 2],
- [0x3098, 1],
- [0x309a, 0],
- [0x30ff, 2],
- [0x3104, 1],
- [0x312f, 2],
- [0x3130, 1],
- [0x318e, 2],
- [0x318f, 1],
- [0x31e3, 2],
- [0x31ee, 1],
- [0x321e, 2],
- [0x321f, 1],
- [0x3247, 2],
- [0x324f, -1],
- [0x4dbf, 2],
- [0x4dff, 1],
- [0xa48c, 2],
- [0xa48f, 1],
- [0xa4c6, 2],
- [0xa66e, 1],
- [0xa66f, 0],
- [0xa673, 1],
- [0xa67d, 0],
- [0xa69d, 1],
- [0xa69f, 0],
- [0xa6ef, 1],
- [0xa6f1, 0],
- [0xa801, 1],
- [0xa802, 0],
- [0xa805, 1],
- [0xa806, 0],
- [0xa80a, 1],
- [0xa80b, 0],
- [0xa824, 1],
- [0xa826, 0],
- [0xa82b, 1],
- [0xa82c, 0],
- [0xa8c3, 1],
- [0xa8c5, 0],
- [0xa8df, 1],
- [0xa8f1, 0],
- [0xa8fe, 1],
- [0xa8ff, 0],
- [0xa925, 1],
- [0xa92d, 0],
- [0xa946, 1],
- [0xa951, 0],
- [0xa95f, 1],
- [0xa97c, 2],
- [0xa97f, 1],
- [0xa982, 0],
- [0xa9b2, 1],
- [0xa9b3, 0],
- [0xa9b5, 1],
- [0xa9b9, 0],
- [0xa9bb, 1],
- [0xa9bd, 0],
- [0xa9e4, 1],
- [0xa9e5, 0],
- [0xaa28, 1],
- [0xaa2e, 0],
- [0xaa30, 1],
- [0xaa32, 0],
- [0xaa34, 1],
- [0xaa36, 0],
- [0xaa42, 1],
- [0xaa43, 0],
- [0xaa4b, 1],
- [0xaa4c, 0],
- [0xaa7b, 1],
- [0xaa7c, 0],
- [0xaaaf, 1],
- [0xaab0, 0],
- [0xaab1, 1],
- [0xaab4, 0],
- [0xaab6, 1],
- [0xaab8, 0],
- [0xaabd, 1],
- [0xaabf, 0],
- [0xaac0, 1],
- [0xaac1, 0],
- [0xaaeb, 1],
- [0xaaed, 0],
- [0xaaf5, 1],
- [0xaaf6, 0],
- [0xabe4, 1],
- [0xabe5, 0],
- [0xabe7, 1],
- [0xabe8, 0],
- [0xabec, 1],
- [0xabed, 0],
- [0xabff, 1],
- [0xd7a3, 2],
- [0xdfff, 1],
- [0xf8ff, -1],
- [0xfaff, 2],
- [0xfb1d, 1],
- [0xfb1e, 0],
- [0xfdff, 1],
- [0xfe0f, 0],
- [0xfe19, 2],
- [0xfe1f, 1],
- [0xfe2f, 0],
- [0xfe52, 2],
- [0xfe53, 1],
- [0xfe66, 2],
- [0xfe67, 1],
- [0xfe6b, 2],
- [0xff00, 1],
- [0xff60, 2],
- [0xffdf, 1],
- [0xffe6, 2],
- [0xfffc, 1],
- [0xfffd, -1],
- [0x101fc, 1],
- [0x101fd, 0],
- [0x102df, 1],
- [0x102e0, 0],
- [0x10375, 1],
- [0x1037a, 0],
- [0x10a00, 1],
- [0x10a03, 0],
- [0x10a04, 1],
- [0x10a06, 0],
- [0x10a0b, 1],
- [0x10a0f, 0],
- [0x10a37, 1],
- [0x10a3a, 0],
- [0x10a3e, 1],
- [0x10a3f, 0],
- [0x10ae4, 1],
- [0x10ae6, 0],
- [0x10d23, 1],
- [0x10d27, 0],
- [0x10eaa, 1],
- [0x10eac, 0],
- [0x10efc, 1],
- [0x10eff, 0],
- [0x10f45, 1],
- [0x10f50, 0],
- [0x10f81, 1],
- [0x10f85, 0],
- [0x11000, 1],
- [0x11001, 0],
- [0x11037, 1],
- [0x11046, 0],
- [0x1106f, 1],
- [0x11070, 0],
- [0x11072, 1],
- [0x11074, 0],
- [0x1107e, 1],
- [0x11081, 0],
- [0x110b2, 1],
- [0x110b6, 0],
- [0x110b8, 1],
- [0x110ba, 0],
- [0x110c1, 1],
- [0x110c2, 0],
- [0x110ff, 1],
- [0x11102, 0],
- [0x11126, 1],
- [0x1112b, 0],
- [0x1112c, 1],
- [0x11134, 0],
- [0x11172, 1],
- [0x11173, 0],
- [0x1117f, 1],
- [0x11181, 0],
- [0x111b5, 1],
- [0x111be, 0],
- [0x111c8, 1],
- [0x111cc, 0],
- [0x111ce, 1],
- [0x111cf, 0],
- [0x1122e, 1],
- [0x11231, 0],
- [0x11233, 1],
- [0x11234, 0],
- [0x11235, 1],
- [0x11237, 0],
- [0x1123d, 1],
- [0x1123e, 0],
- [0x11240, 1],
- [0x11241, 0],
- [0x112de, 1],
- [0x112df, 0],
- [0x112e2, 1],
- [0x112ea, 0],
- [0x112ff, 1],
- [0x11301, 0],
- [0x1133a, 1],
- [0x1133c, 0],
- [0x1133f, 1],
- [0x11340, 0],
- [0x11365, 1],
- [0x1136c, 0],
- [0x1136f, 1],
- [0x11374, 0],
- [0x11437, 1],
- [0x1143f, 0],
- [0x11441, 1],
- [0x11444, 0],
- [0x11445, 1],
- [0x11446, 0],
- [0x1145d, 1],
- [0x1145e, 0],
- [0x114b2, 1],
- [0x114b8, 0],
- [0x114b9, 1],
- [0x114ba, 0],
- [0x114be, 1],
- [0x114c0, 0],
- [0x114c1, 1],
- [0x114c3, 0],
- [0x115b1, 1],
- [0x115b5, 0],
- [0x115bb, 1],
- [0x115bd, 0],
- [0x115be, 1],
- [0x115c0, 0],
- [0x115db, 1],
- [0x115dd, 0],
- [0x11632, 1],
- [0x1163a, 0],
- [0x1163c, 1],
- [0x1163d, 0],
- [0x1163e, 1],
- [0x11640, 0],
- [0x116aa, 1],
- [0x116ab, 0],
- [0x116ac, 1],
- [0x116ad, 0],
- [0x116af, 1],
- [0x116b5, 0],
- [0x116b6, 1],
- [0x116b7, 0],
- [0x1171c, 1],
- [0x1171f, 0],
- [0x11721, 1],
- [0x11725, 0],
- [0x11726, 1],
- [0x1172b, 0],
- [0x1182e, 1],
- [0x11837, 0],
- [0x11838, 1],
- [0x1183a, 0],
- [0x1193a, 1],
- [0x1193c, 0],
- [0x1193d, 1],
- [0x1193e, 0],
- [0x11942, 1],
- [0x11943, 0],
- [0x119d3, 1],
- [0x119d7, 0],
- [0x119d9, 1],
- [0x119db, 0],
- [0x119df, 1],
- [0x119e0, 0],
- [0x11a00, 1],
- [0x11a0a, 0],
- [0x11a32, 1],
- [0x11a38, 0],
- [0x11a3a, 1],
- [0x11a3e, 0],
- [0x11a46, 1],
- [0x11a47, 0],
- [0x11a50, 1],
- [0x11a56, 0],
- [0x11a58, 1],
- [0x11a5b, 0],
- [0x11a89, 1],
- [0x11a96, 0],
- [0x11a97, 1],
- [0x11a99, 0],
- [0x11c2f, 1],
- [0x11c36, 0],
- [0x11c37, 1],
- [0x11c3d, 0],
- [0x11c3e, 1],
- [0x11c3f, 0],
- [0x11c91, 1],
- [0x11ca7, 0],
- [0x11ca9, 1],
- [0x11cb0, 0],
- [0x11cb1, 1],
- [0x11cb3, 0],
- [0x11cb4, 1],
- [0x11cb6, 0],
- [0x11d30, 1],
- [0x11d36, 0],
- [0x11d39, 1],
- [0x11d3a, 0],
- [0x11d3b, 1],
- [0x11d3d, 0],
- [0x11d3e, 1],
- [0x11d45, 0],
- [0x11d46, 1],
- [0x11d47, 0],
- [0x11d8f, 1],
- [0x11d91, 0],
- [0x11d94, 1],
- [0x11d95, 0],
- [0x11d96, 1],
- [0x11d97, 0],
- [0x11ef2, 1],
- [0x11ef4, 0],
- [0x11eff, 1],
- [0x11f01, 0],
- [0x11f35, 1],
- [0x11f3a, 0],
- [0x11f3f, 1],
- [0x11f40, 0],
- [0x11f41, 1],
- [0x11f42, 0],
- [0x1343f, 1],
- [0x13440, 0],
- [0x13446, 1],
- [0x13455, 0],
- [0x16aef, 1],
- [0x16af4, 0],
- [0x16b2f, 1],
- [0x16b36, 0],
- [0x16f4e, 1],
- [0x16f4f, 0],
- [0x16f8e, 1],
- [0x16f92, 0],
- [0x16fdf, 1],
- [0x16fe3, 2],
- [0x16fe4, 0],
- [0x16fef, 1],
- [0x16ff1, 2],
- [0x16fff, 1],
- [0x187f7, 2],
- [0x187ff, 1],
- [0x18cd5, 2],
- [0x18cff, 1],
- [0x18d08, 2],
- [0x1afef, 1],
- [0x1aff3, 2],
- [0x1aff4, 1],
- [0x1affb, 2],
- [0x1affc, 1],
- [0x1affe, 2],
- [0x1afff, 1],
- [0x1b122, 2],
- [0x1b131, 1],
- [0x1b132, 2],
- [0x1b14f, 1],
- [0x1b152, 2],
- [0x1b154, 1],
- [0x1b155, 2],
- [0x1b163, 1],
- [0x1b167, 2],
- [0x1b16f, 1],
- [0x1b2fb, 2],
- [0x1bc9c, 1],
- [0x1bc9e, 0],
- [0x1ceff, 1],
- [0x1cf2d, 0],
- [0x1cf2f, 1],
- [0x1cf46, 0],
- [0x1d166, 1],
- [0x1d169, 0],
- [0x1d17a, 1],
- [0x1d182, 0],
- [0x1d184, 1],
- [0x1d18b, 0],
- [0x1d1a9, 1],
- [0x1d1ad, 0],
- [0x1d241, 1],
- [0x1d244, 0],
- [0x1d9ff, 1],
- [0x1da36, 0],
- [0x1da3a, 1],
- [0x1da6c, 0],
- [0x1da74, 1],
- [0x1da75, 0],
- [0x1da83, 1],
- [0x1da84, 0],
- [0x1da9a, 1],
- [0x1da9f, 0],
- [0x1daa0, 1],
- [0x1daaf, 0],
- [0x1dfff, 1],
- [0x1e006, 0],
- [0x1e007, 1],
- [0x1e018, 0],
- [0x1e01a, 1],
- [0x1e021, 0],
- [0x1e022, 1],
- [0x1e024, 0],
- [0x1e025, 1],
- [0x1e02a, 0],
- [0x1e08e, 1],
- [0x1e08f, 0],
- [0x1e12f, 1],
- [0x1e136, 0],
- [0x1e2ad, 1],
- [0x1e2ae, 0],
- [0x1e2eb, 1],
- [0x1e2ef, 0],
- [0x1e4eb, 1],
- [0x1e4ef, 0],
- [0x1e8cf, 1],
- [0x1e8d6, 0],
- [0x1e943, 1],
- [0x1e94a, 0],
- [0x1f003, 1],
- [0x1f004, 2],
- [0x1f0ce, 1],
- [0x1f0cf, 2],
- [0x1f0ff, 1],
- [0x1f10a, -1],
- [0x1f10f, 1],
- [0x1f12d, -1],
- [0x1f12f, 1],
- [0x1f169, -1],
- [0x1f16f, 1],
- [0x1f18d, -1],
- [0x1f18e, 2],
- [0x1f190, -1],
- [0x1f19a, 2],
- [0x1f1ac, -1],
- [0x1f1ff, 1],
- [0x1f202, 2],
- [0x1f20f, 1],
- [0x1f23b, 2],
- [0x1f23f, 1],
- [0x1f248, 2],
- [0x1f24f, 1],
- [0x1f251, 2],
- [0x1f25f, 1],
- [0x1f265, 2],
- [0x1f2ff, 1],
- [0x1f320, 2],
- [0x1f32c, 1],
- [0x1f335, 2],
- [0x1f336, 1],
- [0x1f37c, 2],
- [0x1f37d, 1],
- [0x1f393, 2],
- [0x1f39f, 1],
- [0x1f3ca, 2],
- [0x1f3ce, 1],
- [0x1f3d3, 2],
- [0x1f3df, 1],
- [0x1f3f0, 2],
- [0x1f3f3, 1],
- [0x1f3f4, 2],
- [0x1f3f7, 1],
- [0x1f43e, 2],
- [0x1f43f, 1],
- [0x1f440, 2],
- [0x1f441, 1],
- [0x1f4fc, 2],
- [0x1f4fe, 1],
- [0x1f53d, 2],
- [0x1f54a, 1],
- [0x1f54e, 2],
- [0x1f54f, 1],
- [0x1f567, 2],
- [0x1f579, 1],
- [0x1f57a, 2],
- [0x1f594, 1],
- [0x1f596, 2],
- [0x1f5a3, 1],
- [0x1f5a4, 2],
- [0x1f5fa, 1],
- [0x1f64f, 2],
- [0x1f67f, 1],
- [0x1f6c5, 2],
- [0x1f6cb, 1],
- [0x1f6cc, 2],
- [0x1f6cf, 1],
- [0x1f6d2, 2],
- [0x1f6d4, 1],
- [0x1f6d7, 2],
- [0x1f6db, 1],
- [0x1f6df, 2],
- [0x1f6ea, 1],
- [0x1f6ec, 2],
- [0x1f6f3, 1],
- [0x1f6fc, 2],
- [0x1f7df, 1],
- [0x1f7eb, 2],
- [0x1f7ef, 1],
- [0x1f7f0, 2],
- [0x1f90b, 1],
- [0x1f93a, 2],
- [0x1f93b, 1],
- [0x1f945, 2],
- [0x1f946, 1],
- [0x1f9ff, 2],
- [0x1fa6f, 1],
- [0x1fa7c, 2],
- [0x1fa7f, 1],
- [0x1fa88, 2],
- [0x1fa8f, 1],
- [0x1fabd, 2],
- [0x1fabe, 1],
- [0x1fac5, 2],
- [0x1facd, 1],
- [0x1fadb, 2],
- [0x1fadf, 1],
- [0x1fae8, 2],
- [0x1faef, 1],
- [0x1faf8, 2],
- [0x1ffff, 1],
- [0x2fffd, 2],
- [0x2ffff, 1],
- [0x3fffd, 2],
- [0xe00ff, 1],
- [0xe01ef, 0],
- [0xeffff, 1],
- [0xffffd, -1],
- [0xfffff, 1],
- [0x10fffd, -1],
- [0x7fffffff, 1]
- ].transpose.map(&:freeze)
+ # Fullwidth
+ TYPE_F = /^[#{ %W(
+ \u{3000}
+ \u{FF01}-\u{FF60}
+ \u{FFE0}-\u{FFE6}
+ ).join }]/
+
+ # Halfwidth
+ TYPE_H = /^[#{ %W(
+ \u{20A9}
+ \u{FF61}-\u{FFBE}
+ \u{FFC2}-\u{FFC7}
+ \u{FFCA}-\u{FFCF}
+ \u{FFD2}-\u{FFD7}
+ \u{FFDA}-\u{FFDC}
+ \u{FFE8}-\u{FFEE}
+ ).join }]/
+
+ # Wide
+ TYPE_W = /^[#{ %W(
+ \u{1100}-\u{115F}
+ \u{231A}-\u{231B}
+ \u{2329}-\u{232A}
+ \u{23E9}-\u{23EC}
+ \u{23F0}
+ \u{23F3}
+ \u{25FD}-\u{25FE}
+ \u{2614}-\u{2615}
+ \u{2648}-\u{2653}
+ \u{267F}
+ \u{2693}
+ \u{26A1}
+ \u{26AA}-\u{26AB}
+ \u{26BD}-\u{26BE}
+ \u{26C4}-\u{26C5}
+ \u{26CE}
+ \u{26D4}
+ \u{26EA}
+ \u{26F2}-\u{26F3}
+ \u{26F5}
+ \u{26FA}
+ \u{26FD}
+ \u{2705}
+ \u{270A}-\u{270B}
+ \u{2728}
+ \u{274C}
+ \u{274E}
+ \u{2753}-\u{2755}
+ \u{2757}
+ \u{2795}-\u{2797}
+ \u{27B0}
+ \u{27BF}
+ \u{2B1B}-\u{2B1C}
+ \u{2B50}
+ \u{2B55}
+ \u{2E80}-\u{2E99}
+ \u{2E9B}-\u{2EF3}
+ \u{2F00}-\u{2FD5}
+ \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{31F0}-\u{321E}
+ \u{3220}-\u{3247}
+ \u{3250}-\u{4DBF}
+ \u{4E00}-\u{A48C}
+ \u{A490}-\u{A4C6}
+ \u{A960}-\u{A97C}
+ \u{AC00}-\u{D7A3}
+ \u{F900}-\u{FAFF}
+ \u{FE10}-\u{FE19}
+ \u{FE30}-\u{FE52}
+ \u{FE54}-\u{FE66}
+ \u{FE68}-\u{FE6B}
+ \u{16FE0}-\u{16FE4}
+ \u{16FF0}-\u{16FF1}
+ \u{17000}-\u{187F7}
+ \u{18800}-\u{18CD5}
+ \u{18D00}-\u{18D08}
+ \u{1B000}-\u{1B11E}
+ \u{1B150}-\u{1B152}
+ \u{1B164}-\u{1B167}
+ \u{1B170}-\u{1B2FB}
+ \u{1F004}
+ \u{1F0CF}
+ \u{1F18E}
+ \u{1F191}-\u{1F19A}
+ \u{1F200}-\u{1F202}
+ \u{1F210}-\u{1F23B}
+ \u{1F240}-\u{1F248}
+ \u{1F250}-\u{1F251}
+ \u{1F260}-\u{1F265}
+ \u{1F300}-\u{1F320}
+ \u{1F32D}-\u{1F335}
+ \u{1F337}-\u{1F37C}
+ \u{1F37E}-\u{1F393}
+ \u{1F3A0}-\u{1F3CA}
+ \u{1F3CF}-\u{1F3D3}
+ \u{1F3E0}-\u{1F3F0}
+ \u{1F3F4}
+ \u{1F3F8}-\u{1F43E}
+ \u{1F440}
+ \u{1F442}-\u{1F4FC}
+ \u{1F4FF}-\u{1F53D}
+ \u{1F54B}-\u{1F54E}
+ \u{1F550}-\u{1F567}
+ \u{1F57A}
+ \u{1F595}-\u{1F596}
+ \u{1F5A4}
+ \u{1F5FB}-\u{1F64F}
+ \u{1F680}-\u{1F6C5}
+ \u{1F6CC}
+ \u{1F6D0}-\u{1F6D2}
+ \u{1F6D5}-\u{1F6D7}
+ \u{1F6EB}-\u{1F6EC}
+ \u{1F6F4}-\u{1F6FC}
+ \u{1F7E0}-\u{1F7EB}
+ \u{1F90C}-\u{1F93A}
+ \u{1F93C}-\u{1F945}
+ \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 }]/
+
+ # Narrow
+ TYPE_NA = /^[#{ %W(
+ \u{0020}-\u{007E}
+ \u{00A2}-\u{00A3}
+ \u{00A5}-\u{00A6}
+ \u{00AC}
+ \u{00AF}
+ \u{27E6}-\u{27ED}
+ \u{2985}-\u{2986}
+ ).join }]/
+
+ # Ambiguous
+ TYPE_A = /^[#{ %W(
+ \u{00A1}
+ \u{00A4}
+ \u{00A7}-\u{00A8}
+ \u{00AA}
+ \u{00AD}-\u{00AE}
+ \u{00B0}-\u{00B4}
+ \u{00B6}-\u{00BA}
+ \u{00BC}-\u{00BF}
+ \u{00C6}
+ \u{00D0}
+ \u{00D7}-\u{00D8}
+ \u{00DE}-\u{00E1}
+ \u{00E6}
+ \u{00E8}-\u{00EA}
+ \u{00EC}-\u{00ED}
+ \u{00F0}
+ \u{00F2}-\u{00F3}
+ \u{00F7}-\u{00FA}
+ \u{00FC}
+ \u{00FE}
+ \u{0101}
+ \u{0111}
+ \u{0113}
+ \u{011B}
+ \u{0126}-\u{0127}
+ \u{012B}
+ \u{0131}-\u{0133}
+ \u{0138}
+ \u{013F}-\u{0142}
+ \u{0144}
+ \u{0148}-\u{014B}
+ \u{014D}
+ \u{0152}-\u{0153}
+ \u{0166}-\u{0167}
+ \u{016B}
+ \u{01CE}
+ \u{01D0}
+ \u{01D2}
+ \u{01D4}
+ \u{01D6}
+ \u{01D8}
+ \u{01DA}
+ \u{01DC}
+ \u{0251}
+ \u{0261}
+ \u{02C4}
+ \u{02C7}
+ \u{02C9}-\u{02CB}
+ \u{02CD}
+ \u{02D0}
+ \u{02D8}-\u{02DB}
+ \u{02DD}
+ \u{02DF}
+ \u{0300}-\u{036F}
+ \u{0391}-\u{03A1}
+ \u{03A3}-\u{03A9}
+ \u{03B1}-\u{03C1}
+ \u{03C3}-\u{03C9}
+ \u{0401}
+ \u{0410}-\u{044F}
+ \u{0451}
+ \u{2010}
+ \u{2013}-\u{2016}
+ \u{2018}-\u{2019}
+ \u{201C}-\u{201D}
+ \u{2020}-\u{2022}
+ \u{2024}-\u{2027}
+ \u{2030}
+ \u{2032}-\u{2033}
+ \u{2035}
+ \u{203B}
+ \u{203E}
+ \u{2074}
+ \u{207F}
+ \u{2081}-\u{2084}
+ \u{20AC}
+ \u{2103}
+ \u{2105}
+ \u{2109}
+ \u{2113}
+ \u{2116}
+ \u{2121}-\u{2122}
+ \u{2126}
+ \u{212B}
+ \u{2153}-\u{2154}
+ \u{215B}-\u{215E}
+ \u{2160}-\u{216B}
+ \u{2170}-\u{2179}
+ \u{2189}
+ \u{2190}-\u{2199}
+ \u{21B8}-\u{21B9}
+ \u{21D2}
+ \u{21D4}
+ \u{21E7}
+ \u{2200}
+ \u{2202}-\u{2203}
+ \u{2207}-\u{2208}
+ \u{220B}
+ \u{220F}
+ \u{2211}
+ \u{2215}
+ \u{221A}
+ \u{221D}-\u{2220}
+ \u{2223}
+ \u{2225}
+ \u{2227}-\u{222C}
+ \u{222E}
+ \u{2234}-\u{2237}
+ \u{223C}-\u{223D}
+ \u{2248}
+ \u{224C}
+ \u{2252}
+ \u{2260}-\u{2261}
+ \u{2264}-\u{2267}
+ \u{226A}-\u{226B}
+ \u{226E}-\u{226F}
+ \u{2282}-\u{2283}
+ \u{2286}-\u{2287}
+ \u{2295}
+ \u{2299}
+ \u{22A5}
+ \u{22BF}
+ \u{2312}
+ \u{2460}-\u{24E9}
+ \u{24EB}-\u{254B}
+ \u{2550}-\u{2573}
+ \u{2580}-\u{258F}
+ \u{2592}-\u{2595}
+ \u{25A0}-\u{25A1}
+ \u{25A3}-\u{25A9}
+ \u{25B2}-\u{25B3}
+ \u{25B6}-\u{25B7}
+ \u{25BC}-\u{25BD}
+ \u{25C0}-\u{25C1}
+ \u{25C6}-\u{25C8}
+ \u{25CB}
+ \u{25CE}-\u{25D1}
+ \u{25E2}-\u{25E5}
+ \u{25EF}
+ \u{2605}-\u{2606}
+ \u{2609}
+ \u{260E}-\u{260F}
+ \u{261C}
+ \u{261E}
+ \u{2640}
+ \u{2642}
+ \u{2660}-\u{2661}
+ \u{2663}-\u{2665}
+ \u{2667}-\u{266A}
+ \u{266C}-\u{266D}
+ \u{266F}
+ \u{269E}-\u{269F}
+ \u{26BF}
+ \u{26C6}-\u{26CD}
+ \u{26CF}-\u{26D3}
+ \u{26D5}-\u{26E1}
+ \u{26E3}
+ \u{26E8}-\u{26E9}
+ \u{26EB}-\u{26F1}
+ \u{26F4}
+ \u{26F6}-\u{26F9}
+ \u{26FB}-\u{26FC}
+ \u{26FE}-\u{26FF}
+ \u{273D}
+ \u{2776}-\u{277F}
+ \u{2B56}-\u{2B59}
+ \u{3248}-\u{324F}
+ \u{E000}-\u{F8FF}
+ \u{FE00}-\u{FE0F}
+ \u{FFFD}
+ \u{1F100}-\u{1F10A}
+ \u{1F110}-\u{1F12D}
+ \u{1F130}-\u{1F169}
+ \u{1F170}-\u{1F18D}
+ \u{1F18F}-\u{1F190}
+ \u{1F19B}-\u{1F1AC}
+ \u{E0100}-\u{E01EF}
+ \u{F0000}-\u{FFFFD}
+ \u{100000}-\u{10FFFD}
+ ).join }]/
+
+ # Neutral
+ TYPE_N = /^[#{ %W(
+ \u{0000}-\u{001F}
+ \u{007F}-\u{00A0}
+ \u{00A9}
+ \u{00AB}
+ \u{00B5}
+ \u{00BB}
+ \u{00C0}-\u{00C5}
+ \u{00C7}-\u{00CF}
+ \u{00D1}-\u{00D6}
+ \u{00D9}-\u{00DD}
+ \u{00E2}-\u{00E5}
+ \u{00E7}
+ \u{00EB}
+ \u{00EE}-\u{00EF}
+ \u{00F1}
+ \u{00F4}-\u{00F6}
+ \u{00FB}
+ \u{00FD}
+ \u{00FF}-\u{0100}
+ \u{0102}-\u{0110}
+ \u{0112}
+ \u{0114}-\u{011A}
+ \u{011C}-\u{0125}
+ \u{0128}-\u{012A}
+ \u{012C}-\u{0130}
+ \u{0134}-\u{0137}
+ \u{0139}-\u{013E}
+ \u{0143}
+ \u{0145}-\u{0147}
+ \u{014C}
+ \u{014E}-\u{0151}
+ \u{0154}-\u{0165}
+ \u{0168}-\u{016A}
+ \u{016C}-\u{01CD}
+ \u{01CF}
+ \u{01D1}
+ \u{01D3}
+ \u{01D5}
+ \u{01D7}
+ \u{01D9}
+ \u{01DB}
+ \u{01DD}-\u{0250}
+ \u{0252}-\u{0260}
+ \u{0262}-\u{02C3}
+ \u{02C5}-\u{02C6}
+ \u{02C8}
+ \u{02CC}
+ \u{02CE}-\u{02CF}
+ \u{02D1}-\u{02D7}
+ \u{02DC}
+ \u{02DE}
+ \u{02E0}-\u{02FF}
+ \u{0370}-\u{0377}
+ \u{037A}-\u{037F}
+ \u{0384}-\u{038A}
+ \u{038C}
+ \u{038E}-\u{0390}
+ \u{03AA}-\u{03B0}
+ \u{03C2}
+ \u{03CA}-\u{0400}
+ \u{0402}-\u{040F}
+ \u{0450}
+ \u{0452}-\u{052F}
+ \u{0531}-\u{0556}
+ \u{0559}-\u{058A}
+ \u{058D}-\u{058F}
+ \u{0591}-\u{05C7}
+ \u{05D0}-\u{05EA}
+ \u{05EF}-\u{05F4}
+ \u{0600}-\u{061C}
+ \u{061E}-\u{070D}
+ \u{070F}-\u{074A}
+ \u{074D}-\u{07B1}
+ \u{07C0}-\u{07FA}
+ \u{07FD}-\u{082D}
+ \u{0830}-\u{083E}
+ \u{0840}-\u{085B}
+ \u{085E}
+ \u{0860}-\u{086A}
+ \u{08A0}-\u{08B4}
+ \u{08B6}-\u{08C7}
+ \u{08D3}-\u{0983}
+ \u{0985}-\u{098C}
+ \u{098F}-\u{0990}
+ \u{0993}-\u{09A8}
+ \u{09AA}-\u{09B0}
+ \u{09B2}
+ \u{09B6}-\u{09B9}
+ \u{09BC}-\u{09C4}
+ \u{09C7}-\u{09C8}
+ \u{09CB}-\u{09CE}
+ \u{09D7}
+ \u{09DC}-\u{09DD}
+ \u{09DF}-\u{09E3}
+ \u{09E6}-\u{09FE}
+ \u{0A01}-\u{0A03}
+ \u{0A05}-\u{0A0A}
+ \u{0A0F}-\u{0A10}
+ \u{0A13}-\u{0A28}
+ \u{0A2A}-\u{0A30}
+ \u{0A32}-\u{0A33}
+ \u{0A35}-\u{0A36}
+ \u{0A38}-\u{0A39}
+ \u{0A3C}
+ \u{0A3E}-\u{0A42}
+ \u{0A47}-\u{0A48}
+ \u{0A4B}-\u{0A4D}
+ \u{0A51}
+ \u{0A59}-\u{0A5C}
+ \u{0A5E}
+ \u{0A66}-\u{0A76}
+ \u{0A81}-\u{0A83}
+ \u{0A85}-\u{0A8D}
+ \u{0A8F}-\u{0A91}
+ \u{0A93}-\u{0AA8}
+ \u{0AAA}-\u{0AB0}
+ \u{0AB2}-\u{0AB3}
+ \u{0AB5}-\u{0AB9}
+ \u{0ABC}-\u{0AC5}
+ \u{0AC7}-\u{0AC9}
+ \u{0ACB}-\u{0ACD}
+ \u{0AD0}
+ \u{0AE0}-\u{0AE3}
+ \u{0AE6}-\u{0AF1}
+ \u{0AF9}-\u{0AFF}
+ \u{0B01}-\u{0B03}
+ \u{0B05}-\u{0B0C}
+ \u{0B0F}-\u{0B10}
+ \u{0B13}-\u{0B28}
+ \u{0B2A}-\u{0B30}
+ \u{0B32}-\u{0B33}
+ \u{0B35}-\u{0B39}
+ \u{0B3C}-\u{0B44}
+ \u{0B47}-\u{0B48}
+ \u{0B4B}-\u{0B4D}
+ \u{0B55}-\u{0B57}
+ \u{0B5C}-\u{0B5D}
+ \u{0B5F}-\u{0B63}
+ \u{0B66}-\u{0B77}
+ \u{0B82}-\u{0B83}
+ \u{0B85}-\u{0B8A}
+ \u{0B8E}-\u{0B90}
+ \u{0B92}-\u{0B95}
+ \u{0B99}-\u{0B9A}
+ \u{0B9C}
+ \u{0B9E}-\u{0B9F}
+ \u{0BA3}-\u{0BA4}
+ \u{0BA8}-\u{0BAA}
+ \u{0BAE}-\u{0BB9}
+ \u{0BBE}-\u{0BC2}
+ \u{0BC6}-\u{0BC8}
+ \u{0BCA}-\u{0BCD}
+ \u{0BD0}
+ \u{0BD7}
+ \u{0BE6}-\u{0BFA}
+ \u{0C00}-\u{0C0C}
+ \u{0C0E}-\u{0C10}
+ \u{0C12}-\u{0C28}
+ \u{0C2A}-\u{0C39}
+ \u{0C3D}-\u{0C44}
+ \u{0C46}-\u{0C48}
+ \u{0C4A}-\u{0C4D}
+ \u{0C55}-\u{0C56}
+ \u{0C58}-\u{0C5A}
+ \u{0C60}-\u{0C63}
+ \u{0C66}-\u{0C6F}
+ \u{0C77}-\u{0C8C}
+ \u{0C8E}-\u{0C90}
+ \u{0C92}-\u{0CA8}
+ \u{0CAA}-\u{0CB3}
+ \u{0CB5}-\u{0CB9}
+ \u{0CBC}-\u{0CC4}
+ \u{0CC6}-\u{0CC8}
+ \u{0CCA}-\u{0CCD}
+ \u{0CD5}-\u{0CD6}
+ \u{0CDE}
+ \u{0CE0}-\u{0CE3}
+ \u{0CE6}-\u{0CEF}
+ \u{0CF1}-\u{0CF2}
+ \u{0D00}-\u{0D0C}
+ \u{0D0E}-\u{0D10}
+ \u{0D12}-\u{0D44}
+ \u{0D46}-\u{0D48}
+ \u{0D4A}-\u{0D4F}
+ \u{0D54}-\u{0D63}
+ \u{0D66}-\u{0D7F}
+ \u{0D81}-\u{0D83}
+ \u{0D85}-\u{0D96}
+ \u{0D9A}-\u{0DB1}
+ \u{0DB3}-\u{0DBB}
+ \u{0DBD}
+ \u{0DC0}-\u{0DC6}
+ \u{0DCA}
+ \u{0DCF}-\u{0DD4}
+ \u{0DD6}
+ \u{0DD8}-\u{0DDF}
+ \u{0DE6}-\u{0DEF}
+ \u{0DF2}-\u{0DF4}
+ \u{0E01}-\u{0E3A}
+ \u{0E3F}-\u{0E5B}
+ \u{0E81}-\u{0E82}
+ \u{0E84}
+ \u{0E86}-\u{0E8A}
+ \u{0E8C}-\u{0EA3}
+ \u{0EA5}
+ \u{0EA7}-\u{0EBD}
+ \u{0EC0}-\u{0EC4}
+ \u{0EC6}
+ \u{0EC8}-\u{0ECD}
+ \u{0ED0}-\u{0ED9}
+ \u{0EDC}-\u{0EDF}
+ \u{0F00}-\u{0F47}
+ \u{0F49}-\u{0F6C}
+ \u{0F71}-\u{0F97}
+ \u{0F99}-\u{0FBC}
+ \u{0FBE}-\u{0FCC}
+ \u{0FCE}-\u{0FDA}
+ \u{1000}-\u{10C5}
+ \u{10C7}
+ \u{10CD}
+ \u{10D0}-\u{10FF}
+ \u{1160}-\u{1248}
+ \u{124A}-\u{124D}
+ \u{1250}-\u{1256}
+ \u{1258}
+ \u{125A}-\u{125D}
+ \u{1260}-\u{1288}
+ \u{128A}-\u{128D}
+ \u{1290}-\u{12B0}
+ \u{12B2}-\u{12B5}
+ \u{12B8}-\u{12BE}
+ \u{12C0}
+ \u{12C2}-\u{12C5}
+ \u{12C8}-\u{12D6}
+ \u{12D8}-\u{1310}
+ \u{1312}-\u{1315}
+ \u{1318}-\u{135A}
+ \u{135D}-\u{137C}
+ \u{1380}-\u{1399}
+ \u{13A0}-\u{13F5}
+ \u{13F8}-\u{13FD}
+ \u{1400}-\u{169C}
+ \u{16A0}-\u{16F8}
+ \u{1700}-\u{170C}
+ \u{170E}-\u{1714}
+ \u{1720}-\u{1736}
+ \u{1740}-\u{1753}
+ \u{1760}-\u{176C}
+ \u{176E}-\u{1770}
+ \u{1772}-\u{1773}
+ \u{1780}-\u{17DD}
+ \u{17E0}-\u{17E9}
+ \u{17F0}-\u{17F9}
+ \u{1800}-\u{180E}
+ \u{1810}-\u{1819}
+ \u{1820}-\u{1878}
+ \u{1880}-\u{18AA}
+ \u{18B0}-\u{18F5}
+ \u{1900}-\u{191E}
+ \u{1920}-\u{192B}
+ \u{1930}-\u{193B}
+ \u{1940}
+ \u{1944}-\u{196D}
+ \u{1970}-\u{1974}
+ \u{1980}-\u{19AB}
+ \u{19B0}-\u{19C9}
+ \u{19D0}-\u{19DA}
+ \u{19DE}-\u{1A1B}
+ \u{1A1E}-\u{1A5E}
+ \u{1A60}-\u{1A7C}
+ \u{1A7F}-\u{1A89}
+ \u{1A90}-\u{1A99}
+ \u{1AA0}-\u{1AAD}
+ \u{1AB0}-\u{1AC0}
+ \u{1B00}-\u{1B4B}
+ \u{1B50}-\u{1B7C}
+ \u{1B80}-\u{1BF3}
+ \u{1BFC}-\u{1C37}
+ \u{1C3B}-\u{1C49}
+ \u{1C4D}-\u{1C88}
+ \u{1C90}-\u{1CBA}
+ \u{1CBD}-\u{1CC7}
+ \u{1CD0}-\u{1CFA}
+ \u{1D00}-\u{1DF9}
+ \u{1DFB}-\u{1F15}
+ \u{1F18}-\u{1F1D}
+ \u{1F20}-\u{1F45}
+ \u{1F48}-\u{1F4D}
+ \u{1F50}-\u{1F57}
+ \u{1F59}
+ \u{1F5B}
+ \u{1F5D}
+ \u{1F5F}-\u{1F7D}
+ \u{1F80}-\u{1FB4}
+ \u{1FB6}-\u{1FC4}
+ \u{1FC6}-\u{1FD3}
+ \u{1FD6}-\u{1FDB}
+ \u{1FDD}-\u{1FEF}
+ \u{1FF2}-\u{1FF4}
+ \u{1FF6}-\u{1FFE}
+ \u{2000}-\u{200F}
+ \u{2011}-\u{2012}
+ \u{2017}
+ \u{201A}-\u{201B}
+ \u{201E}-\u{201F}
+ \u{2023}
+ \u{2028}-\u{202F}
+ \u{2031}
+ \u{2034}
+ \u{2036}-\u{203A}
+ \u{203C}-\u{203D}
+ \u{203F}-\u{2064}
+ \u{2066}-\u{2071}
+ \u{2075}-\u{207E}
+ \u{2080}
+ \u{2085}-\u{208E}
+ \u{2090}-\u{209C}
+ \u{20A0}-\u{20A8}
+ \u{20AA}-\u{20AB}
+ \u{20AD}-\u{20BF}
+ \u{20D0}-\u{20F0}
+ \u{2100}-\u{2102}
+ \u{2104}
+ \u{2106}-\u{2108}
+ \u{210A}-\u{2112}
+ \u{2114}-\u{2115}
+ \u{2117}-\u{2120}
+ \u{2123}-\u{2125}
+ \u{2127}-\u{212A}
+ \u{212C}-\u{2152}
+ \u{2155}-\u{215A}
+ \u{215F}
+ \u{216C}-\u{216F}
+ \u{217A}-\u{2188}
+ \u{218A}-\u{218B}
+ \u{219A}-\u{21B7}
+ \u{21BA}-\u{21D1}
+ \u{21D3}
+ \u{21D5}-\u{21E6}
+ \u{21E8}-\u{21FF}
+ \u{2201}
+ \u{2204}-\u{2206}
+ \u{2209}-\u{220A}
+ \u{220C}-\u{220E}
+ \u{2210}
+ \u{2212}-\u{2214}
+ \u{2216}-\u{2219}
+ \u{221B}-\u{221C}
+ \u{2221}-\u{2222}
+ \u{2224}
+ \u{2226}
+ \u{222D}
+ \u{222F}-\u{2233}
+ \u{2238}-\u{223B}
+ \u{223E}-\u{2247}
+ \u{2249}-\u{224B}
+ \u{224D}-\u{2251}
+ \u{2253}-\u{225F}
+ \u{2262}-\u{2263}
+ \u{2268}-\u{2269}
+ \u{226C}-\u{226D}
+ \u{2270}-\u{2281}
+ \u{2284}-\u{2285}
+ \u{2288}-\u{2294}
+ \u{2296}-\u{2298}
+ \u{229A}-\u{22A4}
+ \u{22A6}-\u{22BE}
+ \u{22C0}-\u{2311}
+ \u{2313}-\u{2319}
+ \u{231C}-\u{2328}
+ \u{232B}-\u{23E8}
+ \u{23ED}-\u{23EF}
+ \u{23F1}-\u{23F2}
+ \u{23F4}-\u{2426}
+ \u{2440}-\u{244A}
+ \u{24EA}
+ \u{254C}-\u{254F}
+ \u{2574}-\u{257F}
+ \u{2590}-\u{2591}
+ \u{2596}-\u{259F}
+ \u{25A2}
+ \u{25AA}-\u{25B1}
+ \u{25B4}-\u{25B5}
+ \u{25B8}-\u{25BB}
+ \u{25BE}-\u{25BF}
+ \u{25C2}-\u{25C5}
+ \u{25C9}-\u{25CA}
+ \u{25CC}-\u{25CD}
+ \u{25D2}-\u{25E1}
+ \u{25E6}-\u{25EE}
+ \u{25F0}-\u{25FC}
+ \u{25FF}-\u{2604}
+ \u{2607}-\u{2608}
+ \u{260A}-\u{260D}
+ \u{2610}-\u{2613}
+ \u{2616}-\u{261B}
+ \u{261D}
+ \u{261F}-\u{263F}
+ \u{2641}
+ \u{2643}-\u{2647}
+ \u{2654}-\u{265F}
+ \u{2662}
+ \u{2666}
+ \u{266B}
+ \u{266E}
+ \u{2670}-\u{267E}
+ \u{2680}-\u{2692}
+ \u{2694}-\u{269D}
+ \u{26A0}
+ \u{26A2}-\u{26A9}
+ \u{26AC}-\u{26BC}
+ \u{26C0}-\u{26C3}
+ \u{26E2}
+ \u{26E4}-\u{26E7}
+ \u{2700}-\u{2704}
+ \u{2706}-\u{2709}
+ \u{270C}-\u{2727}
+ \u{2729}-\u{273C}
+ \u{273E}-\u{274B}
+ \u{274D}
+ \u{274F}-\u{2752}
+ \u{2756}
+ \u{2758}-\u{2775}
+ \u{2780}-\u{2794}
+ \u{2798}-\u{27AF}
+ \u{27B1}-\u{27BE}
+ \u{27C0}-\u{27E5}
+ \u{27EE}-\u{2984}
+ \u{2987}-\u{2B1A}
+ \u{2B1D}-\u{2B4F}
+ \u{2B51}-\u{2B54}
+ \u{2B5A}-\u{2B73}
+ \u{2B76}-\u{2B95}
+ \u{2B97}-\u{2C2E}
+ \u{2C30}-\u{2C5E}
+ \u{2C60}-\u{2CF3}
+ \u{2CF9}-\u{2D25}
+ \u{2D27}
+ \u{2D2D}
+ \u{2D30}-\u{2D67}
+ \u{2D6F}-\u{2D70}
+ \u{2D7F}-\u{2D96}
+ \u{2DA0}-\u{2DA6}
+ \u{2DA8}-\u{2DAE}
+ \u{2DB0}-\u{2DB6}
+ \u{2DB8}-\u{2DBE}
+ \u{2DC0}-\u{2DC6}
+ \u{2DC8}-\u{2DCE}
+ \u{2DD0}-\u{2DD6}
+ \u{2DD8}-\u{2DDE}
+ \u{2DE0}-\u{2E52}
+ \u{303F}
+ \u{4DC0}-\u{4DFF}
+ \u{A4D0}-\u{A62B}
+ \u{A640}-\u{A6F7}
+ \u{A700}-\u{A7BF}
+ \u{A7C2}-\u{A7CA}
+ \u{A7F5}-\u{A82C}
+ \u{A830}-\u{A839}
+ \u{A840}-\u{A877}
+ \u{A880}-\u{A8C5}
+ \u{A8CE}-\u{A8D9}
+ \u{A8E0}-\u{A953}
+ \u{A95F}
+ \u{A980}-\u{A9CD}
+ \u{A9CF}-\u{A9D9}
+ \u{A9DE}-\u{A9FE}
+ \u{AA00}-\u{AA36}
+ \u{AA40}-\u{AA4D}
+ \u{AA50}-\u{AA59}
+ \u{AA5C}-\u{AAC2}
+ \u{AADB}-\u{AAF6}
+ \u{AB01}-\u{AB06}
+ \u{AB09}-\u{AB0E}
+ \u{AB11}-\u{AB16}
+ \u{AB20}-\u{AB26}
+ \u{AB28}-\u{AB2E}
+ \u{AB30}-\u{AB6B}
+ \u{AB70}-\u{ABED}
+ \u{ABF0}-\u{ABF9}
+ \u{D7B0}-\u{D7C6}
+ \u{D7CB}-\u{D7FB}
+ \u{FB00}-\u{FB06}
+ \u{FB13}-\u{FB17}
+ \u{FB1D}-\u{FB36}
+ \u{FB38}-\u{FB3C}
+ \u{FB3E}
+ \u{FB40}-\u{FB41}
+ \u{FB43}-\u{FB44}
+ \u{FB46}-\u{FBC1}
+ \u{FBD3}-\u{FD3F}
+ \u{FD50}-\u{FD8F}
+ \u{FD92}-\u{FDC7}
+ \u{FDF0}-\u{FDFD}
+ \u{FE20}-\u{FE2F}
+ \u{FE70}-\u{FE74}
+ \u{FE76}-\u{FEFC}
+ \u{FEFF}
+ \u{FFF9}-\u{FFFC}
+ \u{10000}-\u{1000B}
+ \u{1000D}-\u{10026}
+ \u{10028}-\u{1003A}
+ \u{1003C}-\u{1003D}
+ \u{1003F}-\u{1004D}
+ \u{10050}-\u{1005D}
+ \u{10080}-\u{100FA}
+ \u{10100}-\u{10102}
+ \u{10107}-\u{10133}
+ \u{10137}-\u{1018E}
+ \u{10190}-\u{1019C}
+ \u{101A0}
+ \u{101D0}-\u{101FD}
+ \u{10280}-\u{1029C}
+ \u{102A0}-\u{102D0}
+ \u{102E0}-\u{102FB}
+ \u{10300}-\u{10323}
+ \u{1032D}-\u{1034A}
+ \u{10350}-\u{1037A}
+ \u{10380}-\u{1039D}
+ \u{1039F}-\u{103C3}
+ \u{103C8}-\u{103D5}
+ \u{10400}-\u{1049D}
+ \u{104A0}-\u{104A9}
+ \u{104B0}-\u{104D3}
+ \u{104D8}-\u{104FB}
+ \u{10500}-\u{10527}
+ \u{10530}-\u{10563}
+ \u{1056F}
+ \u{10600}-\u{10736}
+ \u{10740}-\u{10755}
+ \u{10760}-\u{10767}
+ \u{10800}-\u{10805}
+ \u{10808}
+ \u{1080A}-\u{10835}
+ \u{10837}-\u{10838}
+ \u{1083C}
+ \u{1083F}-\u{10855}
+ \u{10857}-\u{1089E}
+ \u{108A7}-\u{108AF}
+ \u{108E0}-\u{108F2}
+ \u{108F4}-\u{108F5}
+ \u{108FB}-\u{1091B}
+ \u{1091F}-\u{10939}
+ \u{1093F}
+ \u{10980}-\u{109B7}
+ \u{109BC}-\u{109CF}
+ \u{109D2}-\u{10A03}
+ \u{10A05}-\u{10A06}
+ \u{10A0C}-\u{10A13}
+ \u{10A15}-\u{10A17}
+ \u{10A19}-\u{10A35}
+ \u{10A38}-\u{10A3A}
+ \u{10A3F}-\u{10A48}
+ \u{10A50}-\u{10A58}
+ \u{10A60}-\u{10A9F}
+ \u{10AC0}-\u{10AE6}
+ \u{10AEB}-\u{10AF6}
+ \u{10B00}-\u{10B35}
+ \u{10B39}-\u{10B55}
+ \u{10B58}-\u{10B72}
+ \u{10B78}-\u{10B91}
+ \u{10B99}-\u{10B9C}
+ \u{10BA9}-\u{10BAF}
+ \u{10C00}-\u{10C48}
+ \u{10C80}-\u{10CB2}
+ \u{10CC0}-\u{10CF2}
+ \u{10CFA}-\u{10D27}
+ \u{10D30}-\u{10D39}
+ \u{10E60}-\u{10E7E}
+ \u{10E80}-\u{10EA9}
+ \u{10EAB}-\u{10EAD}
+ \u{10EB0}-\u{10EB1}
+ \u{10F00}-\u{10F27}
+ \u{10F30}-\u{10F59}
+ \u{10FB0}-\u{10FCB}
+ \u{10FE0}-\u{10FF6}
+ \u{11000}-\u{1104D}
+ \u{11052}-\u{1106F}
+ \u{1107F}-\u{110C1}
+ \u{110CD}
+ \u{110D0}-\u{110E8}
+ \u{110F0}-\u{110F9}
+ \u{11100}-\u{11134}
+ \u{11136}-\u{11147}
+ \u{11150}-\u{11176}
+ \u{11180}-\u{111DF}
+ \u{111E1}-\u{111F4}
+ \u{11200}-\u{11211}
+ \u{11213}-\u{1123E}
+ \u{11280}-\u{11286}
+ \u{11288}
+ \u{1128A}-\u{1128D}
+ \u{1128F}-\u{1129D}
+ \u{1129F}-\u{112A9}
+ \u{112B0}-\u{112EA}
+ \u{112F0}-\u{112F9}
+ \u{11300}-\u{11303}
+ \u{11305}-\u{1130C}
+ \u{1130F}-\u{11310}
+ \u{11313}-\u{11328}
+ \u{1132A}-\u{11330}
+ \u{11332}-\u{11333}
+ \u{11335}-\u{11339}
+ \u{1133B}-\u{11344}
+ \u{11347}-\u{11348}
+ \u{1134B}-\u{1134D}
+ \u{11350}
+ \u{11357}
+ \u{1135D}-\u{11363}
+ \u{11366}-\u{1136C}
+ \u{11370}-\u{11374}
+ \u{11400}-\u{1145B}
+ \u{1145D}-\u{11461}
+ \u{11480}-\u{114C7}
+ \u{114D0}-\u{114D9}
+ \u{11580}-\u{115B5}
+ \u{115B8}-\u{115DD}
+ \u{11600}-\u{11644}
+ \u{11650}-\u{11659}
+ \u{11660}-\u{1166C}
+ \u{11680}-\u{116B8}
+ \u{116C0}-\u{116C9}
+ \u{11700}-\u{1171A}
+ \u{1171D}-\u{1172B}
+ \u{11730}-\u{1173F}
+ \u{11800}-\u{1183B}
+ \u{118A0}-\u{118F2}
+ \u{118FF}-\u{11906}
+ \u{11909}
+ \u{1190C}-\u{11913}
+ \u{11915}-\u{11916}
+ \u{11918}-\u{11935}
+ \u{11937}-\u{11938}
+ \u{1193B}-\u{11946}
+ \u{11950}-\u{11959}
+ \u{119A0}-\u{119A7}
+ \u{119AA}-\u{119D7}
+ \u{119DA}-\u{119E4}
+ \u{11A00}-\u{11A47}
+ \u{11A50}-\u{11AA2}
+ \u{11AC0}-\u{11AF8}
+ \u{11C00}-\u{11C08}
+ \u{11C0A}-\u{11C36}
+ \u{11C38}-\u{11C45}
+ \u{11C50}-\u{11C6C}
+ \u{11C70}-\u{11C8F}
+ \u{11C92}-\u{11CA7}
+ \u{11CA9}-\u{11CB6}
+ \u{11D00}-\u{11D06}
+ \u{11D08}-\u{11D09}
+ \u{11D0B}-\u{11D36}
+ \u{11D3A}
+ \u{11D3C}-\u{11D3D}
+ \u{11D3F}-\u{11D47}
+ \u{11D50}-\u{11D59}
+ \u{11D60}-\u{11D65}
+ \u{11D67}-\u{11D68}
+ \u{11D6A}-\u{11D8E}
+ \u{11D90}-\u{11D91}
+ \u{11D93}-\u{11D98}
+ \u{11DA0}-\u{11DA9}
+ \u{11EE0}-\u{11EF8}
+ \u{11FB0}
+ \u{11FC0}-\u{11FF1}
+ \u{11FFF}-\u{12399}
+ \u{12400}-\u{1246E}
+ \u{12470}-\u{12474}
+ \u{12480}-\u{12543}
+ \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{16A6F}
+ \u{16AD0}-\u{16AED}
+ \u{16AF0}-\u{16AF5}
+ \u{16B00}-\u{16B45}
+ \u{16B50}-\u{16B59}
+ \u{16B5B}-\u{16B61}
+ \u{16B63}-\u{16B77}
+ \u{16B7D}-\u{16B8F}
+ \u{16E40}-\u{16E9A}
+ \u{16F00}-\u{16F4A}
+ \u{16F4F}-\u{16F87}
+ \u{16F8F}-\u{16F9F}
+ \u{1BC00}-\u{1BC6A}
+ \u{1BC70}-\u{1BC7C}
+ \u{1BC80}-\u{1BC88}
+ \u{1BC90}-\u{1BC99}
+ \u{1BC9C}-\u{1BCA3}
+ \u{1D000}-\u{1D0F5}
+ \u{1D100}-\u{1D126}
+ \u{1D129}-\u{1D1E8}
+ \u{1D200}-\u{1D245}
+ \u{1D2E0}-\u{1D2F3}
+ \u{1D300}-\u{1D356}
+ \u{1D360}-\u{1D378}
+ \u{1D400}-\u{1D454}
+ \u{1D456}-\u{1D49C}
+ \u{1D49E}-\u{1D49F}
+ \u{1D4A2}
+ \u{1D4A5}-\u{1D4A6}
+ \u{1D4A9}-\u{1D4AC}
+ \u{1D4AE}-\u{1D4B9}
+ \u{1D4BB}
+ \u{1D4BD}-\u{1D4C3}
+ \u{1D4C5}-\u{1D505}
+ \u{1D507}-\u{1D50A}
+ \u{1D50D}-\u{1D514}
+ \u{1D516}-\u{1D51C}
+ \u{1D51E}-\u{1D539}
+ \u{1D53B}-\u{1D53E}
+ \u{1D540}-\u{1D544}
+ \u{1D546}
+ \u{1D54A}-\u{1D550}
+ \u{1D552}-\u{1D6A5}
+ \u{1D6A8}-\u{1D7CB}
+ \u{1D7CE}-\u{1DA8B}
+ \u{1DA9B}-\u{1DA9F}
+ \u{1DAA1}-\u{1DAAF}
+ \u{1E000}-\u{1E006}
+ \u{1E008}-\u{1E018}
+ \u{1E01B}-\u{1E021}
+ \u{1E023}-\u{1E024}
+ \u{1E026}-\u{1E02A}
+ \u{1E100}-\u{1E12C}
+ \u{1E130}-\u{1E13D}
+ \u{1E140}-\u{1E149}
+ \u{1E14E}-\u{1E14F}
+ \u{1E2C0}-\u{1E2F9}
+ \u{1E2FF}
+ \u{1E800}-\u{1E8C4}
+ \u{1E8C7}-\u{1E8D6}
+ \u{1E900}-\u{1E94B}
+ \u{1E950}-\u{1E959}
+ \u{1E95E}-\u{1E95F}
+ \u{1EC71}-\u{1ECB4}
+ \u{1ED01}-\u{1ED3D}
+ \u{1EE00}-\u{1EE03}
+ \u{1EE05}-\u{1EE1F}
+ \u{1EE21}-\u{1EE22}
+ \u{1EE24}
+ \u{1EE27}
+ \u{1EE29}-\u{1EE32}
+ \u{1EE34}-\u{1EE37}
+ \u{1EE39}
+ \u{1EE3B}
+ \u{1EE42}
+ \u{1EE47}
+ \u{1EE49}
+ \u{1EE4B}
+ \u{1EE4D}-\u{1EE4F}
+ \u{1EE51}-\u{1EE52}
+ \u{1EE54}
+ \u{1EE57}
+ \u{1EE59}
+ \u{1EE5B}
+ \u{1EE5D}
+ \u{1EE5F}
+ \u{1EE61}-\u{1EE62}
+ \u{1EE64}
+ \u{1EE67}-\u{1EE6A}
+ \u{1EE6C}-\u{1EE72}
+ \u{1EE74}-\u{1EE77}
+ \u{1EE79}-\u{1EE7C}
+ \u{1EE7E}
+ \u{1EE80}-\u{1EE89}
+ \u{1EE8B}-\u{1EE9B}
+ \u{1EEA1}-\u{1EEA3}
+ \u{1EEA5}-\u{1EEA9}
+ \u{1EEAB}-\u{1EEBB}
+ \u{1EEF0}-\u{1EEF1}
+ \u{1F000}-\u{1F003}
+ \u{1F005}-\u{1F02B}
+ \u{1F030}-\u{1F093}
+ \u{1F0A0}-\u{1F0AE}
+ \u{1F0B1}-\u{1F0BF}
+ \u{1F0C1}-\u{1F0CE}
+ \u{1F0D1}-\u{1F0F5}
+ \u{1F10B}-\u{1F10F}
+ \u{1F12E}-\u{1F12F}
+ \u{1F16A}-\u{1F16F}
+ \u{1F1AD}
+ \u{1F1E6}-\u{1F1FF}
+ \u{1F321}-\u{1F32C}
+ \u{1F336}
+ \u{1F37D}
+ \u{1F394}-\u{1F39F}
+ \u{1F3CB}-\u{1F3CE}
+ \u{1F3D4}-\u{1F3DF}
+ \u{1F3F1}-\u{1F3F3}
+ \u{1F3F5}-\u{1F3F7}
+ \u{1F43F}
+ \u{1F441}
+ \u{1F4FD}-\u{1F4FE}
+ \u{1F53E}-\u{1F54A}
+ \u{1F54F}
+ \u{1F568}-\u{1F579}
+ \u{1F57B}-\u{1F594}
+ \u{1F597}-\u{1F5A3}
+ \u{1F5A5}-\u{1F5FA}
+ \u{1F650}-\u{1F67F}
+ \u{1F6C6}-\u{1F6CB}
+ \u{1F6CD}-\u{1F6CF}
+ \u{1F6D3}-\u{1F6D4}
+ \u{1F6E0}-\u{1F6EA}
+ \u{1F6F0}-\u{1F6F3}
+ \u{1F700}-\u{1F773}
+ \u{1F780}-\u{1F7D8}
+ \u{1F800}-\u{1F80B}
+ \u{1F810}-\u{1F847}
+ \u{1F850}-\u{1F859}
+ \u{1F860}-\u{1F887}
+ \u{1F890}-\u{1F8AD}
+ \u{1F8B0}-\u{1F8B1}
+ \u{1F900}-\u{1F90B}
+ \u{1F93B}
+ \u{1F946}
+ \u{1FA00}-\u{1FA53}
+ \u{1FA60}-\u{1FA6D}
+ \u{1FB00}-\u{1FB92}
+ \u{1FB94}-\u{1FBCA}
+ \u{1FBF0}-\u{1FBF9}
+ \u{E0001}
+ \u{E0020}-\u{E007F}
+ ).join }]/
end
diff --git a/lib/reline/version.rb b/lib/reline/version.rb
index b75d874adb..67a3d694bd 100644
--- a/lib/reline/version.rb
+++ b/lib/reline/version.rb
@@ -1,3 +1,3 @@
module Reline
- VERSION = '0.5.10'
+ VERSION = '0.3.2'
end
diff --git a/lib/reline/windows.rb b/lib/reline/windows.rb
new file mode 100644
index 0000000000..b952329911
--- /dev/null
+++ b/lib/reline/windows.rb
@@ -0,0 +1,497 @@
+require 'fiddle/import'
+
+class Reline::Windows
+ def self.encoding
+ Encoding::UTF_8
+ end
+
+ def self.win?
+ true
+ end
+
+ def self.win_legacy_console?
+ @@legacy_console
+ end
+
+ def self.set_default_key_bindings(config)
+ {
+ [224, 72] => :ed_prev_history, # ↑
+ [224, 80] => :ed_next_history, # ↓
+ [224, 77] => :ed_next_char, # →
+ [224, 75] => :ed_prev_char, # ←
+ [224, 83] => :key_delete, # Del
+ [224, 71] => :ed_move_to_beg, # Home
+ [224, 79] => :ed_move_to_end, # End
+ [ 0, 41] => :ed_unassigned, # input method on/off
+ [ 0, 72] => :ed_prev_history, # ↑
+ [ 0, 80] => :ed_next_history, # ↓
+ [ 0, 77] => :ed_next_char, # →
+ [ 0, 75] => :ed_prev_char, # ←
+ [ 0, 83] => :key_delete, # Del
+ [ 0, 71] => :ed_move_to_beg, # Home
+ [ 0, 79] => :ed_move_to_end # End
+ }.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, 32] => :em_set_mark, # M-<space>
+ [24, 24] => :em_exchange_mark, # C-x C-x
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ end
+
+ # Emulate ANSI key sequence.
+ {
+ [27, 91, 90] => :completion_journey_up, # S-Tab
+ }.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)
+ end
+ end
+
+ if defined? JRUBY_VERSION
+ require 'win32api'
+ else
+ class Win32API
+ DLL = {}
+ TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
+ POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
+
+ WIN32_TYPES = "VPpNnLlIi"
+ DL_TYPES = "0SSI"
+
+ def initialize(dllname, func, import, export = "0", calltype = :stdcall)
+ @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
+ import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
+ export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
+ calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
+
+ handle = DLL[dllname] ||=
+ begin
+ Fiddle.dlopen(dllname)
+ rescue Fiddle::DLError
+ raise unless File.extname(dllname).empty?
+ Fiddle.dlopen(dllname + ".dll")
+ end
+
+ @func = Fiddle::Function.new(handle[func], import, export, calltype)
+ rescue Fiddle::DLError => e
+ raise LoadError, e.message, e.backtrace
+ end
+
+ def call(*args)
+ import = @proto.split("")
+ args.each_with_index do |x, i|
+ args[i], = [x == 0 ? nil : x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
+ args[i], = [x].pack("I").unpack("i") if import[i] == "I"
+ end
+ ret, = @func.call(*args)
+ return ret || 0
+ end
+ end
+ end
+
+ VK_RETURN = 0x0D
+ VK_MENU = 0x12 # ALT key
+ VK_LMENU = 0xA4
+ VK_CONTROL = 0x11
+ VK_SHIFT = 0x10
+ VK_DIVIDE = 0x6F
+
+ KEY_EVENT = 0x01
+ WINDOW_BUFFER_SIZE_EVENT = 0x04
+
+ CAPSLOCK_ON = 0x0080
+ ENHANCED_KEY = 0x0100
+ LEFT_ALT_PRESSED = 0x0002
+ LEFT_CTRL_PRESSED = 0x0008
+ NUMLOCK_ON = 0x0020
+ RIGHT_ALT_PRESSED = 0x0001
+ RIGHT_CTRL_PRESSED = 0x0004
+ SCROLLLOCK_ON = 0x0040
+ SHIFT_PRESSED = 0x0010
+
+ VK_TAB = 0x09
+ VK_END = 0x23
+ VK_HOME = 0x24
+ VK_LEFT = 0x25
+ VK_UP = 0x26
+ VK_RIGHT = 0x27
+ VK_DOWN = 0x28
+ VK_DELETE = 0x2E
+
+ STD_INPUT_HANDLE = -10
+ STD_OUTPUT_HANDLE = -11
+ FILE_TYPE_PIPE = 0x0003
+ FILE_NAME_INFO = 2
+ @@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
+ @@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
+ @@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
+ @@GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
+ @@SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
+ @@GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
+ @@FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
+ @@ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
+ @@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
+ @@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
+ @@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
+ @@ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
+ @@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
+ @@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
+ @@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
+ @@SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
+
+ @@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
+ @@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
+ @@WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
+
+ private_class_method def self.getconsolemode
+ mode = "\000\000\000\000"
+ @@GetConsoleMode.call(@@hConsoleHandle, mode)
+ mode.unpack1('L')
+ end
+
+ private_class_method def self.setconsolemode(mode)
+ @@SetConsoleMode.call(@@hConsoleHandle, mode)
+ end
+
+ @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
+ #if @@legacy_console
+ # setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ # @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
+ #end
+
+ @@input_buf = []
+ @@output_buf = []
+
+ @@output = STDOUT
+
+ def self.msys_tty?(io = @@hConsoleInputHandle)
+ # check if fd is a pipe
+ if @@GetFileType.call(io) != FILE_TYPE_PIPE
+ return false
+ end
+
+ bufsize = 1024
+ p_buffer = "\0" * bufsize
+ res = @@GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
+ return false if res == 0
+
+ # get pipe name: p_buffer layout is:
+ # struct _FILE_NAME_INFO {
+ # DWORD FileNameLength;
+ # WCHAR FileName[1];
+ # } FILE_NAME_INFO
+ len = p_buffer[0, 4].unpack1("L")
+ name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
+
+ # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
+ # or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX')
+ name =~ /(msys-|cygwin-).*-pty/ ? true : false
+ end
+
+ KEY_MAP = [
+ # It's treated as Meta+Enter on Windows.
+ [ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
+ [ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
+
+ # It's treated as Meta+Space on Windows.
+ [ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
+
+ # Emulate getwch() key sequences.
+ [ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
+ [ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
+ [ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
+ [ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
+ [ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
+ [ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
+ [ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
+
+ # Emulate ANSI key sequence.
+ [ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
+ ]
+
+ @@hsg = nil
+
+ def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
+
+ # high-surrogate
+ if 0xD800 <= char_code and char_code <= 0xDBFF
+ @@hsg = char_code
+ return
+ end
+ # low-surrogate
+ if 0xDC00 <= char_code and char_code <= 0xDFFF
+ if @@hsg
+ char_code = 0x10000 + (@@hsg - 0xD800) * 0x400 + char_code - 0xDC00
+ @@hsg = nil
+ else
+ # no high-surrogate. ignored.
+ return
+ end
+ else
+ # ignore high-surrogate without low-surrogate if there
+ @@hsg = nil
+ end
+
+ key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
+
+ match = KEY_MAP.find { |args,| key.matches?(**args) }
+ unless match.nil?
+ @@output_buf.concat(match.last)
+ return
+ end
+
+ # no char, only control keys
+ return if key.char_code == 0 and key.control_keys.any?
+
+ @@output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
+
+ @@output_buf.concat(key.char.bytes)
+ end
+
+ def self.check_input_event
+ num_of_events = 0.chr * 8
+ while @@output_buf.empty?
+ Reline.core.line_editor.resize
+ if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
+ # prevent for background consolemode change
+ @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
+ next
+ end
+ next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
+ input_records = 0.chr * 20 * 80
+ read_event = 0.chr * 4
+ if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_records, 80, read_event) != 0
+ read_events = read_event.unpack1('L')
+ 0.upto(read_events) do |idx|
+ input_record = input_records[idx * 20, 20]
+ event = input_record[0, 2].unpack1('s*')
+ case event
+ when WINDOW_BUFFER_SIZE_EVENT
+ @@winch_handler.()
+ when KEY_EVENT
+ key_down = input_record[4, 4].unpack1('l*')
+ repeat_count = input_record[8, 2].unpack1('s*')
+ virtual_key_code = input_record[10, 2].unpack1('s*')
+ virtual_scan_code = input_record[12, 2].unpack1('s*')
+ char_code = input_record[14, 2].unpack1('S*')
+ control_key_state = input_record[16, 2].unpack1('S*')
+ is_key_down = key_down.zero? ? false : true
+ if is_key_down
+ process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def self.getc
+ check_input_event
+ @@output_buf.shift
+ end
+
+ def self.ungetc(c)
+ @@output_buf.unshift(c)
+ end
+
+ def self.in_pasting?
+ not self.empty_buffer?
+ end
+
+ def self.empty_buffer?
+ if not @@output_buf.empty?
+ false
+ elsif @@kbhit.call == 0
+ true
+ else
+ false
+ end
+ end
+
+ def self.get_console_screen_buffer_info
+ # CONSOLE_SCREEN_BUFFER_INFO
+ # [ 0,2] dwSize.X
+ # [ 2,2] dwSize.Y
+ # [ 4,2] dwCursorPositions.X
+ # [ 6,2] dwCursorPositions.Y
+ # [ 8,2] wAttributes
+ # [10,2] srWindow.Left
+ # [12,2] srWindow.Top
+ # [14,2] srWindow.Right
+ # [16,2] srWindow.Bottom
+ # [18,2] dwMaximumWindowSize.X
+ # [20,2] dwMaximumWindowSize.Y
+ csbi = 0.chr * 22
+ return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
+ csbi
+ end
+
+ def self.get_screen_size
+ unless csbi = get_console_screen_buffer_info
+ return [1, 1]
+ end
+ csbi[0, 4].unpack('SS').reverse
+ end
+
+ def self.cursor_pos
+ unless csbi = get_console_screen_buffer_info
+ return Reline::CursorPos.new(0, 0)
+ end
+ x = csbi[4, 2].unpack1('s')
+ y = csbi[6, 2].unpack1('s')
+ Reline::CursorPos.new(x, y)
+ end
+
+ def self.move_cursor_column(val)
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, cursor_pos.y * 65536 + val)
+ end
+
+ def self.move_cursor_up(val)
+ if val > 0
+ y = cursor_pos.y - val
+ y = 0 if y < 0
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, y * 65536 + cursor_pos.x)
+ elsif val < 0
+ move_cursor_down(-val)
+ end
+ end
+
+ def self.move_cursor_down(val)
+ if val > 0
+ return unless csbi = get_console_screen_buffer_info
+ screen_height = get_screen_size.first
+ y = cursor_pos.y + val
+ y = screen_height - 1 if y > (screen_height - 1)
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, (cursor_pos.y + val) * 65536 + cursor_pos.x)
+ elsif val < 0
+ move_cursor_up(-val)
+ end
+ end
+
+ def self.erase_after_cursor
+ return unless csbi = get_console_screen_buffer_info
+ attributes = csbi[8, 2].unpack1('S')
+ cursor = csbi[4, 4].unpack1('L')
+ written = 0.chr * 4
+ @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
+ @@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
+ end
+
+ def self.scroll_down(val)
+ return if val < 0
+ return unless csbi = get_console_screen_buffer_info
+ buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
+ screen_height = window_bottom - window_top + 1
+ val = screen_height if val > screen_height
+
+ if @@legacy_console || window_left != 0
+ # unless ENABLE_VIRTUAL_TERMINAL,
+ # if srWindow.Left != 0 then it's conhost.exe hosted console
+ # and puts "\n" causes horizontal scroll. its glitch.
+ # FYI irb write from culumn 1, so this gives no gain.
+ scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4')
+ destination_origin = 0 # y * 65536 + x
+ fill = [' '.ord, attributes].pack('SS')
+ @@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
+ else
+ origin_x = x + 1
+ origin_y = y - window_top + 1
+ @@output.write [
+ (origin_y != screen_height) ? "\e[#{screen_height};H" : nil,
+ "\n" * val,
+ (origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil
+ ].join
+ end
+ end
+
+ def self.clear_screen
+ if @@legacy_console
+ return unless csbi = get_console_screen_buffer_info
+ buffer_width, _buffer_lines, attributes, window_top, window_bottom = csbi.unpack('ss@8S@12sx2s')
+ fill_length = buffer_width * (window_bottom - window_top + 1)
+ screen_topleft = window_top * 65536
+ written = 0.chr * 4
+ @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, fill_length, screen_topleft, written)
+ @@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, fill_length, screen_topleft, written)
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, screen_topleft)
+ else
+ @@output.write "\e[2J" "\e[H"
+ end
+ end
+
+ def self.set_screen_size(rows, columns)
+ raise NotImplementedError
+ end
+
+ def self.hide_cursor
+ size = 100
+ visible = 0 # 0 means false
+ cursor_info = [size, visible].pack('Li')
+ @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
+ end
+
+ def self.show_cursor
+ size = 100
+ visible = 1 # 1 means true
+ cursor_info = [size, visible].pack('Li')
+ @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
+ end
+
+ def self.set_winch_handler(&handler)
+ @@winch_handler = handler
+ end
+
+ def self.prep
+ # do nothing
+ nil
+ end
+
+ def self.deprep(otio)
+ # do nothing
+ end
+
+ class KeyEventRecord
+
+ attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
+
+ def initialize(virtual_key_code, char_code, control_key_state)
+ @virtual_key_code = virtual_key_code
+ @char_code = char_code
+ @control_key_state = control_key_state
+ @enhanced = control_key_state & ENHANCED_KEY != 0
+
+ (@control_keys = []).tap do |control_keys|
+ # symbols must be sorted to make comparison is easier later on
+ control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
+ control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
+ control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
+ end.freeze
+ end
+
+ def char
+ @char_code.chr(Encoding::UTF_8)
+ end
+
+ def enhanced?
+ @enhanced
+ end
+
+ # Verifies if the arguments match with this key event.
+ # Nil arguments are ignored, but at least one must be passed as non-nil.
+ # To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
+ def matches?(control_keys: nil, virtual_key_code: nil, char_code: nil)
+ raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
+
+ (control_keys.nil? || [*control_keys].sort == @control_keys) &&
+ (virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
+ (char_code.nil? || char_code == @char_code)
+ end
+
+ end
+end
diff --git a/lib/resolv.gemspec b/lib/resolv.gemspec
index 6b83e303d7..db256dc1b0 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.2"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/resolv.rb b/lib/resolv.rb
index 57fd173750..61c9c7d5cf 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -37,8 +37,6 @@ end
class Resolv
- VERSION = "0.3.0"
-
##
# Looks up the first IP address for +name+.
@@ -84,8 +82,8 @@ class Resolv
##
# Creates a new Resolv using +resolvers+.
- def initialize(resolvers=nil, use_ipv6: nil)
- @resolvers = resolvers || [Hosts.new, DNS.new(DNS::Config.default_config_hash.merge(use_ipv6: use_ipv6))]
+ def initialize(resolvers=[Hosts.new, DNS.new])
+ @resolvers = resolvers
end
##
@@ -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|
@@ -312,8 +310,6 @@ class Resolv
# String:: Path to a file using /etc/resolv.conf's format.
# Hash:: Must contain :nameserver, :search and :ndots keys.
# :nameserver_port can be used to specify port number of nameserver address.
- # :raise_timeout_errors can be used to raise timeout errors
- # as exceptions instead of treating the same as an NXDOMAIN response.
#
# The value of :nameserver should be an address string or
# an array of address strings.
@@ -410,11 +406,6 @@ class Resolv
end
def use_ipv6? # :nodoc:
- use_ipv6 = @config.use_ipv6?
- unless use_ipv6.nil?
- return use_ipv6
- end
-
begin
list = Socket.ip_address_list
rescue NotImplementedError
@@ -757,7 +748,7 @@ class Resolv
next if @socks_hash[bind_host]
begin
sock = UDPSocket.new(af)
- rescue Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT
+ rescue Errno::EAFNOSUPPORT
next # The kernel doesn't support the address family.
end
@socks << sock
@@ -974,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]]
@@ -1013,7 +1004,6 @@ class Resolv
@mutex.synchronize {
unless @initialized
@nameserver_port = []
- @use_ipv6 = nil
@search = nil
@ndots = 1
case @config_info
@@ -1038,12 +1028,8 @@ class Resolv
if config_hash.include? :nameserver_port
@nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
end
- if config_hash.include? :use_ipv6
- @use_ipv6 = config_hash[:use_ipv6]
- end
@search = config_hash[:search] if config_hash.include? :search
@ndots = config_hash[:ndots] if config_hash.include? :ndots
- @raise_timeout_errors = config_hash[:raise_timeout_errors]
if @nameserver_port.empty?
@nameserver_port << ['0.0.0.0', Port]
@@ -1097,10 +1083,6 @@ class Resolv
@nameserver_port
end
- def use_ipv6?
- @use_ipv6
- end
-
def generate_candidates(name)
candidates = nil
name = Name.create(name)
@@ -1134,7 +1116,6 @@ class Resolv
def resolv(name)
candidates = generate_candidates(name)
timeouts = @timeouts || generate_timeouts
- timeout_error = false
begin
candidates.each {|candidate|
begin
@@ -1146,13 +1127,11 @@ class Resolv
end
}
}
- timeout_error = true
raise ResolvError.new("DNS resolv timeout: #{name}")
rescue NXDomain
end
}
rescue ResolvError
- raise if @raise_timeout_errors && timeout_error
end
end
@@ -1508,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
@@ -1539,15 +1518,13 @@ class Resolv
id, flag, qdcount, ancount, nscount, arcount =
msg.get_unpack('nnnnnn')
o.id = id
- o.tc = (flag >> 9) & 1
- o.rcode = flag & 15
- return o unless o.tc.zero?
-
o.qr = (flag >> 15) & 1
o.opcode = (flag >> 11) & 15
o.aa = (flag >> 10) & 1
+ o.tc = (flag >> 9) & 1
o.rd = (flag >> 8) & 1
o.ra = (flag >> 7) & 1
+ o.rcode = flag & 15
(1..qdcount).each {
name, typeclass = msg.get_question
o.add_question(name, typeclass)
@@ -1639,14 +1616,6 @@ class Resolv
strings
end
- def get_list
- [].tap do |values|
- while @index < @limit
- values << yield
- end
- end
- end
-
def get_name
return Name.new(self.get_labels)
end
@@ -1708,378 +1677,6 @@ class Resolv
end
##
- # SvcParams for service binding RRs. [RFC9460]
-
- class SvcParams
- include Enumerable
-
- ##
- # Create a list of SvcParams with the given initial content.
- #
- # +params+ has to be an enumerable of +SvcParam+s.
- # If its content has +SvcParam+s with the duplicate key,
- # the one appears last takes precedence.
-
- def initialize(params = [])
- @params = {}
-
- params.each do |param|
- add param
- end
- end
-
- ##
- # Get SvcParam for the given +key+ in this list.
-
- def [](key)
- @params[canonical_key(key)]
- end
-
- ##
- # Get the number of SvcParams in this list.
-
- def count
- @params.count
- end
-
- ##
- # Get whether this list is empty.
-
- def empty?
- @params.empty?
- end
-
- ##
- # Add the SvcParam +param+ to this list, overwriting the existing one with the same key.
-
- def add(param)
- @params[param.class.key_number] = param
- end
-
- ##
- # Remove the +SvcParam+ with the given +key+ and return it.
-
- def delete(key)
- @params.delete(canonical_key(key))
- end
-
- ##
- # Enumerate the +SvcParam+s in this list.
-
- def each(&block)
- return enum_for(:each) unless block
- @params.each_value(&block)
- end
-
- def encode(msg) # :nodoc:
- @params.keys.sort.each do |key|
- msg.put_pack('n', key)
- msg.put_length16 do
- @params.fetch(key).encode(msg)
- end
- end
- end
-
- def self.decode(msg) # :nodoc:
- params = msg.get_list do
- key, = msg.get_unpack('n')
- msg.get_length16 do
- SvcParam::ClassHash[key].decode(msg)
- end
- end
-
- return self.new(params)
- end
-
- private
-
- def canonical_key(key) # :nodoc:
- case key
- when Integer
- key
- when /\Akey(\d+)\z/
- Integer($1)
- when Symbol
- SvcParam::ClassHash[key].key_number
- else
- raise TypeError, 'key must be either String or Symbol'
- end
- end
- end
-
-
- ##
- # Base class for SvcParam. [RFC9460]
-
- class SvcParam
-
- ##
- # Get the presentation name of the SvcParamKey.
-
- def self.key_name
- const_get(:KeyName)
- end
-
- ##
- # Get the registered number of the SvcParamKey.
-
- def self.key_number
- const_get(:KeyNumber)
- end
-
- ClassHash = Hash.new do |h, key| # :nodoc:
- case key
- when Integer
- Generic.create(key)
- when /\Akey(?<key>\d+)\z/
- Generic.create(key.to_int)
- when Symbol
- raise KeyError, "unknown key #{key}"
- else
- raise TypeError, 'key must be either String or Symbol'
- end
- end
-
- ##
- # Generic SvcParam abstract class.
-
- class Generic < SvcParam
-
- ##
- # SvcParamValue in wire-format byte string.
-
- attr_reader :value
-
- ##
- # Create generic SvcParam
-
- def initialize(value)
- @value = value
- end
-
- def encode(msg) # :nodoc:
- msg.put_bytes(@value)
- end
-
- def self.decode(msg) # :nodoc:
- return self.new(msg.get_bytes)
- end
-
- def self.create(key_number)
- c = Class.new(Generic)
- key_name = :"key#{key_number}"
- c.const_set(:KeyName, key_name)
- c.const_set(:KeyNumber, key_number)
- self.const_set(:"Key#{key_number}", c)
- ClassHash[key_name] = ClassHash[key_number] = c
- return c
- end
- end
-
- ##
- # "mandatory" SvcParam -- Mandatory keys in service binding RR
-
- class Mandatory < SvcParam
- KeyName = :mandatory
- KeyNumber = 0
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Mandatory keys.
-
- attr_reader :keys
-
- ##
- # Initialize "mandatory" ScvParam.
-
- def initialize(keys)
- @keys = keys.map(&:to_int)
- end
-
- def encode(msg) # :nodoc:
- @keys.sort.each do |key|
- msg.put_pack('n', key)
- end
- end
-
- def self.decode(msg) # :nodoc:
- keys = msg.get_list { msg.get_unpack('n')[0] }
- return self.new(keys)
- end
- end
-
- ##
- # "alpn" SvcParam -- Additional supported protocols
-
- class ALPN < SvcParam
- KeyName = :alpn
- KeyNumber = 1
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Supported protocol IDs.
-
- attr_reader :protocol_ids
-
- ##
- # Initialize "alpn" ScvParam.
-
- def initialize(protocol_ids)
- @protocol_ids = protocol_ids.map(&:to_str)
- end
-
- def encode(msg) # :nodoc:
- msg.put_string_list(@protocol_ids)
- end
-
- def self.decode(msg) # :nodoc:
- return self.new(msg.get_string_list)
- end
- end
-
- ##
- # "no-default-alpn" SvcParam -- No support for default protocol
-
- class NoDefaultALPN < SvcParam
- KeyName = :'no-default-alpn'
- KeyNumber = 2
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- def encode(msg) # :nodoc:
- # no payload
- end
-
- def self.decode(msg) # :nodoc:
- return self.new
- end
- end
-
- ##
- # "port" SvcParam -- Port for alternative endpoint
-
- class Port < SvcParam
- KeyName = :port
- KeyNumber = 3
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Port number.
-
- attr_reader :port
-
- ##
- # Initialize "port" ScvParam.
-
- def initialize(port)
- @port = port.to_int
- end
-
- def encode(msg) # :nodoc:
- msg.put_pack('n', @port)
- end
-
- def self.decode(msg) # :nodoc:
- port, = msg.get_unpack('n')
- return self.new(port)
- end
- end
-
- ##
- # "ipv4hint" SvcParam -- IPv4 address hints
-
- class IPv4Hint < SvcParam
- KeyName = :ipv4hint
- KeyNumber = 4
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Set of IPv4 addresses.
-
- attr_reader :addresses
-
- ##
- # Initialize "ipv4hint" ScvParam.
-
- def initialize(addresses)
- @addresses = addresses.map {|address| IPv4.create(address) }
- end
-
- def encode(msg) # :nodoc:
- @addresses.each do |address|
- msg.put_bytes(address.address)
- end
- end
-
- def self.decode(msg) # :nodoc:
- addresses = msg.get_list { IPv4.new(msg.get_bytes(4)) }
- return self.new(addresses)
- end
- end
-
- ##
- # "ipv6hint" SvcParam -- IPv6 address hints
-
- class IPv6Hint < SvcParam
- KeyName = :ipv6hint
- KeyNumber = 6
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Set of IPv6 addresses.
-
- attr_reader :addresses
-
- ##
- # Initialize "ipv6hint" ScvParam.
-
- def initialize(addresses)
- @addresses = addresses.map {|address| IPv6.create(address) }
- end
-
- def encode(msg) # :nodoc:
- @addresses.each do |address|
- msg.put_bytes(address.address)
- end
- end
-
- def self.decode(msg) # :nodoc:
- addresses = msg.get_list { IPv6.new(msg.get_bytes(16)) }
- return self.new(addresses)
- end
- end
-
- ##
- # "dohpath" SvcParam -- DNS over HTTPS path template [RFC9461]
-
- class DoHPath < SvcParam
- KeyName = :dohpath
- KeyNumber = 7
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # URI template for DoH queries.
-
- attr_reader :template
-
- ##
- # Initialize "dohpath" ScvParam.
-
- def initialize(template)
- @template = template.encode('utf-8')
- end
-
- def encode(msg) # :nodoc:
- msg.put_bytes(@template)
- end
-
- def self.decode(msg) # :nodoc:
- template = msg.get_bytes.force_encoding('utf-8')
- return self.new(template)
- end
- end
- end
-
- ##
# A DNS query abstract class.
class Query
@@ -2731,7 +2328,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:
@@ -2742,84 +2339,6 @@ class Resolv
return self.new(priority, weight, port, target)
end
end
-
- ##
- # Common implementation for SVCB-compatible resource records.
-
- class ServiceBinding
-
- ##
- # Create a service binding resource record.
-
- def initialize(priority, target, params = [])
- @priority = priority.to_int
- @target = Name.create(target)
- @params = SvcParams.new(params)
- end
-
- ##
- # The priority of this target host.
- #
- # The range is 0-65535.
- # If set to 0, this RR is in AliasMode. Otherwise, it is in ServiceMode.
-
- attr_reader :priority
-
- ##
- # The domain name of the target host.
-
- attr_reader :target
-
- ##
- # The service paramters for the target host.
-
- attr_reader :params
-
- ##
- # Whether this RR is in AliasMode.
-
- def alias_mode?
- self.priority == 0
- end
-
- ##
- # Whether this RR is in ServiceMode.
-
- def service_mode?
- !alias_mode?
- end
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack("n", @priority)
- msg.put_name(@target, compress: false)
- @params.encode(msg)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- priority, = msg.get_unpack("n")
- target = msg.get_name
- params = SvcParams.decode(msg)
- return self.new(priority, target, params)
- end
- end
-
- ##
- # SVCB resource record [RFC9460]
-
- class SVCB < ServiceBinding
- TypeValue = 64
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
- end
-
- ##
- # HTTPS resource record [RFC9460]
-
- class HTTPS < ServiceBinding
- TypeValue = 65
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
- end
end
end
end
@@ -3039,7 +2558,11 @@ class Resolv
attr_reader :address
def to_s # :nodoc:
- sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn")).sub(/(^|:)0(:0)+(:|$)/, '::')
+ address = sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn"))
+ unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
+ address.sub!(/(^|:)0(:|$)/, '::')
+ end
+ return address
end
def inspect # :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..a9f2aeda8d
--- /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"
+
+ # 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
+
+ # 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
+
+ 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/.document b/lib/ruby_vm/rjit/.document
deleted file mode 100644
index 0a603afe3d..0000000000
--- a/lib/ruby_vm/rjit/.document
+++ /dev/null
@@ -1 +0,0 @@
-stats.rb
diff --git a/lib/ruby_vm/rjit/assembler.rb b/lib/ruby_vm/rjit/assembler.rb
deleted file mode 100644
index 645072d11b..0000000000
--- a/lib/ruby_vm/rjit/assembler.rb
+++ /dev/null
@@ -1,1140 +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, imm32 (Mod 01: [reg]+disp8)
- in [QwordPtr[R64 => left_reg, IMM8 => left_disp], 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: Mod01, reg: 7, rm: left_reg],
- disp: left_disp,
- imm: imm32(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 db00c4cd11..0000000000
--- a/lib/ruby_vm/rjit/c_pointer.rb
+++ /dev/null
@@ -1,394 +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
-
- # Basically Immediate but without #* to skip auto-dereference of structs.
- class Array
- attr_reader :type
-
- # @param addr [Integer]
- # @param type [Class] RubyVM::RJIT::CType::*
- def initialize(addr, type)
- @addr = addr
- @type = type
- end
-
- # Array access
- def [](index)
- @type.new(@addr)[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)
- @type.new(@addr)[index] = value
- end
-
- private
-
- def self.define(block)
- Class.new(self) do
- define_method(:initialize) do |addr|
- super(addr, block.call)
- end
- end
- 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.nil? && 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 3b313a658b..0000000000
--- a/lib/ruby_vm/rjit/c_type.rb
+++ /dev/null
@@ -1,99 +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 Array
- def self.new(&block)
- CPointer.with_class_name('Array', block.object_id.to_s) do
- CPointer::Array.define(block)
- end
- 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 260bd98671..0000000000
--- a/lib/ruby_vm/rjit/code_block.rb
+++ /dev/null
@@ -1,91 +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] = [] } if dump_disasm?
- @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 if dump_disasm?
- 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) if dump_disasm?
- 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
-
- def dump_disasm?
- C.rjit_opts.dump_disasm
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/compiler.rb b/lib/ruby_vm/rjit/compiler.rb
deleted file mode 100644
index e5c3adf0ec..0000000000
--- a/lib/ruby_vm/rjit/compiler.rb
+++ /dev/null
@@ -1,518 +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)
- return unless supported_platform?
- 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.class}: #{e.message}"
- STDERR.puts e.backtrace
- 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
-
- def supported_platform?
- return @supported_platform if defined?(@supported_platform)
- @supported_platform = RUBY_PLATFORM.match?(/x86_64/).tap do |supported|
- warn "warning: RJIT does not support #{RUBY_PLATFORM} yet" unless supported
- 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 a2a7ecc6dc..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[idx]
- if idx == local_idx
- self.temp_types[stack_idx] = self.local_types[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 289963d855..0000000000
--- a/lib/ruby_vm/rjit/insn_compiler.rb
+++ /dev/null
@@ -1,5972 +0,0 @@
-# frozen_string_literal: true
-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_no_warnings(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 = compile_branchif(branch_stub)
- branch_stub.compile.call(asm)
- end
-
- EndBlock
- end
-
- def compile_branchif(branch_stub) # Proc escapes arguments in memory
- 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
- 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 = compile_branchunless(branch_stub)
- branch_stub.compile.call(asm)
- end
-
- EndBlock
- end
-
- def compile_branchunless(branch_stub) # Proc escapes arguments in memory
- 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
- 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 = compile_branchnil(branch_stub)
- branch_stub.compile.call(asm)
- end
-
- EndBlock
- end
-
- def compile_branchnil(branch_stub) # Proc escapes arguments in memory
- 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
- 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, to_value(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 hierarchy 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 = compile_jit_chain_guard(branch_stub, opcode:)
- branch_stub.compile.call(asm)
- else
- asm.public_send(opcode, side_exit)
- end
- end
-
- def compile_jit_chain_guard(branch_stub, opcode:) # Proc escapes arguments in memory
- 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
- 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 = compile_jit_return(branch_stub, cfp_offset:)
- 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
-
- def compile_jit_return(branch_stub, cfp_offset:) # Proc escapes arguments in memory
- 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
- 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 = compile_jit_direct_jump(branch_stub, comment:)
- branch_stub.compile.call(asm)
- end
-
- def compile_jit_direct_jump(branch_stub, comment:) # Proc escapes arguments in memory
- 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
- 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 7e353c698e..0000000000
--- a/lib/ruby_vm/rjit/stats.rb
+++ /dev/null
@@ -1,191 +0,0 @@
-# frozen_string_literal: true
-module RubyVM::RJIT
- # Return a Hash for \RJIT statistics. \--rjit-stats makes more information available.
- 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
- stats[:vm_insns_count] = C.rb_vm_insns_count
-
- # 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
-
- # :nodoc: all
- 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 b739c8074f..26b0b1da7e 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -9,7 +8,7 @@
require "rbconfig"
module Gem
- VERSION = "3.5.22"
+ VERSION = "3.4.6".freeze
end
# Must be first since it unloads the prelude from 1.9.2
@@ -115,6 +114,11 @@ require_relative "rubygems/errors"
module Gem
RUBYGEMS_DIR = __dir__
+ # Taint support is deprecated in Ruby 2.7.
+ # This allows switching ".untaint" to ".tap(&Gem::UNTAINT)",
+ # to avoid deprecation warnings in Ruby 2.7.
+ UNTAINT = RUBY_VERSION < "2.7" ? :untaint.to_sym : proc {}
+
##
# An Array of Regexps that match windows Ruby platforms.
@@ -206,7 +210,7 @@ module Gem
end
end
- true
+ return true
end
def self.needs
@@ -334,6 +338,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)
@@ -424,7 +438,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 = {}
@@ -450,7 +464,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
@@ -484,14 +498,14 @@ 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:
glob_with_suffixes = "#{glob}#{Gem.suffix_pattern}"
$LOAD_PATH.map do |load_path|
Gem::Util.glob_files_in_dir(glob_with_suffixes, load_path)
- end.flatten.select {|file| File.file? file }
+ end.flatten.select {|file| File.file? file.tap(&Gem::UNTAINT) }
end
##
@@ -519,7 +533,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
##
@@ -567,7 +581,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
@@ -599,16 +613,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.
#
@@ -737,7 +741,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
@@ -753,14 +757,21 @@ 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)
- File.binread(path)
+ open_file(path, "rb+") do |io|
+ io.read
+ end
+ rescue Errno::EACCES, Errno::EROFS
+ open_file(path, "rb") do |io|
+ io.read
+ end
end
##
# Safely write a file in binary mode on all platforms.
-
def self.write_binary(path, data)
- File.binwrite(path, data)
+ open_file(path, "wb") do |io|
+ io.write data
+ end
rescue Errno::ENOSPC
# If we ran out of space but the file exists, it's *guaranteed* to be corrupted.
File.delete(path) if File.exist?(path)
@@ -768,37 +779,26 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
- # Open a file with given flags
+ # Open a file with given flags, and on Windows protect access with flock
def self.open_file(path, flags, &block)
- File.open(path, flags, &block)
- end
-
- ##
- # Open a file with given flags, and protect access with a file lock
-
- def self.open_file_with_lock(path, &block)
- file_lock = "#{path}.lock"
- open_file_with_flock(file_lock, &block)
- ensure
- FileUtils.rm_f file_lock
- end
-
- ##
- # Open a file with given flags, and protect access with flock
-
- def self.open_file_with_flock(path, &block)
- # read-write mode is used rather than read-only in order to support NFS
- mode = IO::RDWR | IO::APPEND | IO::CREAT | IO::BINARY
- mode |= IO::SHARE_DELETE if IO.const_defined?(:SHARE_DELETE)
-
- File.open(path, mode) do |io|
- begin
- io.flock(File::LOCK_EX)
- rescue Errno::ENOSYS, Errno::ENOTSUP
+ File.open(path, flags) do |io|
+ if !java_platform? && win_platform?
+ begin
+ io.flock(File::LOCK_EX)
+ rescue Errno::ENOSYS, Errno::ENOTSUP
+ end
end
yield io
end
+ rescue Errno::ENOLCK # NFS
+ if Thread.main != Thread.current
+ raise
+ else
+ File.open(path, flags) do |io|
+ yield io
+ end
+ end
end
##
@@ -808,7 +808,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
@@ -824,7 +824,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
def self.env_requirement(gem_name)
@env_requirements_by_name ||= {}
@env_requirements_by_name[gem_name] ||= begin
- req = ENV["GEM_REQUIREMENT_#{gem_name.upcase}"] || ">= 0"
+ req = ENV["GEM_REQUIREMENT_#{gem_name.upcase}"] || ">= 0".freeze
Gem::Requirement.create(req)
end
end
@@ -855,7 +855,8 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Returns the version of the latest release-version of gem +name+
def self.latest_version_for(name)
- latest_spec_for(name)&.version
+ spec = latest_spec_for name
+ spec && spec.version
end
##
@@ -865,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
@@ -913,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
##
@@ -947,14 +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
-
- ##
- # Suffixes for dynamic library require-able paths.
-
- def self.dynamic_library_suffixes
- @dynamic_library_suffixes ||= suffixes - [".rb"]
+ end,
+ ].compact.uniq
end
##
@@ -968,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
@@ -1000,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
@@ -1021,13 +1016,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
- # Is this platform FreeBSD
-
- def self.freebsd_platform?
- RbConfig::CONFIG["host_os"].to_s.include?("bsd")
- end
-
- ##
# Load +plugins+ as Ruby files
def self.load_plugin_files(plugins) # :nodoc:
@@ -1035,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
@@ -1101,6 +1089,8 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
end
+ path.tap(&Gem::UNTAINT)
+
unless File.file? path
return unless raise_exception
@@ -1112,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
@@ -1162,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
@@ -1231,16 +1223,9 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
##
# Find a Gem::Specification of default gem from +path+
- def find_default_spec(path)
- @path_to_default_spec_map[path]
- end
-
- ##
- # Find an unresolved Gem::Specification of default gem from +path+
-
def find_unresolved_default_spec(path)
default_spec = @path_to_default_spec_map[path]
- default_spec if default_spec && loaded_specs[default_spec.name] != default_spec
+ return default_spec if default_spec && loaded_specs[default_spec.name] != default_spec
end
##
@@ -1319,7 +1304,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/".freeze
autoload :ConfigFile, File.expand_path("rubygems/config_file", __dir__)
- autoload :CIDetector, File.expand_path("rubygems/ci_detector", __dir__)
autoload :Dependency, File.expand_path("rubygems/dependency", __dir__)
autoload :DependencyList, File.expand_path("rubygems/dependency_list", __dir__)
autoload :Installer, File.expand_path("rubygems/installer", __dir__)
@@ -1366,17 +1350,6 @@ begin
rescue LoadError
end
-# TruffleRuby >= 24 defines REUSE_AS_BINARY_ON_TRUFFLERUBY in defaults/truffleruby.
-# However, TruffleRuby < 24 defines REUSE_AS_BINARY_ON_TRUFFLERUBY directly in its copy
-# of lib/rubygems/platform.rb, so it is not defined if RubyGems is updated (gem update --system).
-# Instead, we define it here in that case, similar to bundler/lib/bundler/rubygems_ext.rb.
-# We must define it here and not in platform.rb because platform.rb is loaded before defaults/truffleruby.
-class Gem::Platform
- if RUBY_ENGINE == "truffleruby" && !defined?(REUSE_AS_BINARY_ON_TRUFFLERUBY)
- REUSE_AS_BINARY_ON_TRUFFLERUBY = %w[libv8 libv8-node sorbet-static].freeze
- end
-end
-
##
# Loads the default specs.
Gem::Specification.load_defaults
@@ -1386,7 +1359,7 @@ require_relative "rubygems/core_ext/kernel_gem"
path = File.join(__dir__, "rubygems/core_ext/kernel_require.rb")
# When https://bugs.ruby-lang.org/issues/17259 is available, there is no need to override Kernel#warn
if RUBY_ENGINE == "truffleruby" ||
- RUBY_ENGINE == "ruby"
+ (RUBY_ENGINE == "ruby" && RUBY_VERSION >= "3.0")
file = "<internal:#{path}>"
else
require_relative "rubygems/core_ext/kernel_warn"
diff --git a/lib/rubygems/available_set.rb b/lib/rubygems/available_set.rb
index 0af80cc3db..58b601f6b0 100644
--- a/lib/rubygems/available_set.rb
+++ b/lib/rubygems/available_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
class Gem::AvailableSet
include Enumerable
@@ -27,7 +26,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 +69,7 @@ class Gem::AvailableSet
end
def all_specs
- @set.map(&:spec)
+ @set.map {|t| t.spec }
end
def match_platform!
@@ -105,14 +104,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 +146,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 308d94b0fc..dcc64e6409 100644
--- a/lib/rubygems/basic_specification.rb
+++ b/lib/rubygems/basic_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# BasicSpecification is an abstract class which implements some common code
# used by both Specification and StubSpecification.
@@ -71,57 +70,32 @@ class Gem::BasicSpecification
# Return true if this spec can require +file+.
def contains_requirable_file?(file)
- if ignored?
- if platform == Gem::Platform::RUBY || Gem::Platform.local === platform
- warn "Ignoring #{full_name} because its extensions are not built. " \
+ if @ignored
+ return false
+ elsif missing_extensions?
+ @ignored = true
+
+ 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
return false
end
- is_soext = file.end_with?(".so", ".o")
-
- if is_soext
- have_file? file.delete_suffix(File.extname(file)), Gem.dynamic_library_suffixes
- else
- have_file? file, Gem.suffixes
- end
- end
-
- ##
- # Return true if this spec should be ignored because it's missing extensions.
-
- def ignored?
- return @ignored unless @ignored.nil?
-
- @ignored = missing_extensions?
+ have_file? file, Gem.suffixes
end
def default_gem?
- !loaded_from.nil? &&
+ loaded_from &&
File.dirname(loaded_from) == Gem.default_specifications_dir
end
##
- # Regular gems take precedence over default gems
-
- def default_gem_priority
- default_gem? ? 1 : -1
- end
-
- ##
- # Gems higher up in +gem_path+ take precedence
-
- def base_dir_priority(gem_path)
- gem_path.index(base_dir) || gem_path.size
- end
-
- ##
# Returns full path to the directory where gem's extensions are installed.
def extension_dir
- @extension_dir ||= File.expand_path(File.join(extensions_dir, full_name))
+ @extension_dir ||= File.expand_path(File.join(extensions_dir, full_name)).tap(&Gem::UNTAINT)
end
##
@@ -135,7 +109,9 @@ class Gem::BasicSpecification
def find_full_gem_path # :nodoc:
# TODO: also, shouldn't it default to full_name if it hasn't been written?
- File.expand_path File.join(gems_dir, full_name)
+ path = File.expand_path File.join(gems_dir, full_name)
+ path.tap(&Gem::UNTAINT)
+ path
end
private :find_full_gem_path
@@ -156,22 +132,9 @@ class Gem::BasicSpecification
def full_name
if platform == Gem::Platform::RUBY || platform.nil?
- "#{name}-#{version}"
- else
- "#{name}-#{version}-#{platform}"
- end
- end
-
- ##
- # Returns the full name of this Gem (see `Gem::BasicSpecification#full_name`).
- # Information about where the gem is installed is also included if not
- # installed in the default GEM_HOME.
-
- def full_name_with_location
- if base_dir != Gem.dir
- "#{full_name} in #{base_dir}"
+ "#{name}-#{version}".dup.tap(&Gem::UNTAINT)
else
- full_name
+ "#{name}-#{version}-#{platform}".dup.tap(&Gem::UNTAINT)
end
end
@@ -181,15 +144,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
- 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
##
@@ -197,7 +160,7 @@ class Gem::BasicSpecification
def datadir
# TODO: drop the extra ", gem_name" which is uselessly redundant
- File.expand_path(File.join(gems_dir, full_name, "data", name))
+ File.expand_path(File.join(gems_dir, full_name, "data", name)).tap(&Gem::UNTAINT)
end
##
@@ -207,14 +170,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
@@ -304,9 +271,9 @@ 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]
+ Dir[glob].map {|f| f.tap(&Gem::UNTAINT) } # FIX our tests are broken, run w/ SAFE=1
end
##
@@ -321,17 +288,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}"
+ "#{self.full_gem_path}/#{dirs}".dup.tap(&Gem::UNTAINT)
end
##
@@ -356,19 +323,15 @@ 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|
- base = File.join(gems_dir, full_name, path, file)
+ base = File.join(gems_dir, full_name, path.tap(&Gem::UNTAINT), file).tap(&Gem::UNTAINT)
suffixes.any? {|suf| File.file? base + suf }
end
diff --git a/lib/rubygems/bundler_version_finder.rb b/lib/rubygems/bundler_version_finder.rb
index 4ebbad1c0c..f6fad0bd83 100644
--- a/lib/rubygems/bundler_version_finder.rb
+++ b/lib/rubygems/bundler_version_finder.rb
@@ -21,7 +21,7 @@ module Gem::BundlerVersionFinder
end
def self.bundle_update_bundler_version
- return unless ["bundle", "bundler"].include? File.basename($0)
+ return unless File.basename($0) == "bundle".freeze
return unless "update".start_with?(ARGV.first || " ")
bundler_version = nil
update_index = nil
@@ -47,12 +47,12 @@ module Gem::BundlerVersionFinder
def self.lockfile_contents
gemfile = ENV["BUNDLE_GEMFILE"]
- gemfile = nil if gemfile&.empty?
+ gemfile = nil if gemfile && gemfile.empty?
unless gemfile
begin
Gem::Util.traverse_parents(Dir.pwd) do |directory|
- next unless gemfile = Gem::GEM_DEP_FILES.find {|f| File.file?(f) }
+ next unless gemfile = Gem::GEM_DEP_FILES.find {|f| File.file?(f.tap(&Gem::UNTAINT)) }
gemfile = File.join directory, gemfile
break
@@ -65,9 +65,9 @@ module Gem::BundlerVersionFinder
return unless gemfile
lockfile = case gemfile
- when "gems.rb" then "gems.locked"
- else "#{gemfile}.lock"
- end
+ when "gems.rb" then "gems.locked"
+ else "#{gemfile}.lock"
+ end.dup.tap(&Gem::UNTAINT)
return unless File.file?(lockfile)
diff --git a/lib/rubygems/ci_detector.rb b/lib/rubygems/ci_detector.rb
deleted file mode 100644
index 7a2d4ee29a..0000000000
--- a/lib/rubygems/ci_detector.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-module Gem
- module CIDetector
- # NOTE: Any changes made here will need to be made to both lib/rubygems/ci_detector.rb and
- # bundler/lib/bundler/ci_detector.rb (which are enforced duplicates).
- # TODO: Drop that duplication once bundler drops support for RubyGems 3.4
- #
- # ## Recognized CI providers, their signifiers, and the relevant docs ##
- #
- # Travis CI - CI, TRAVIS https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
- # Cirrus CI - CI, CIRRUS_CI https://cirrus-ci.org/guide/writing-tasks/#environment-variables
- # Circle CI - CI, CIRCLECI https://circleci.com/docs/variables/#built-in-environment-variables
- # Gitlab CI - CI, GITLAB_CI https://docs.gitlab.com/ee/ci/variables/
- # AppVeyor - CI, APPVEYOR https://www.appveyor.com/docs/environment-variables/
- # CodeShip - CI_NAME https://docs.cloudbees.com/docs/cloudbees-codeship/latest/pro-builds-and-configuration/environment-variables#_default_environment_variables
- # dsari - CI, DSARI https://github.com/rfinnie/dsari#running
- # Jenkins - BUILD_NUMBER https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
- # TeamCity - TEAMCITY_VERSION https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters
- # Appflow - CI_BUILD_ID https://ionic.io/docs/appflow/automation/environments#predefined-environments
- # TaskCluster - TASKCLUSTER_ROOT_URL https://docs.taskcluster.net/docs/manual/design/env-vars
- # Semaphore - CI, SEMAPHORE https://docs.semaphoreci.com/ci-cd-environment/environment-variables/
- # BuildKite - CI, BUILDKITE https://buildkite.com/docs/pipelines/environment-variables
- # GoCD - GO_SERVER_URL https://docs.gocd.org/current/faq/dev_use_current_revision_in_build.html
- # GH Actions - CI, GITHUB_ACTIONS https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
- #
- # ### Some "standard" ENVs that multiple providers may set ###
- #
- # * CI - this is set by _most_ (but not all) CI providers now; it's approaching a standard.
- # * CI_NAME - Not as frequently used, but some providers set this to specify their own name
-
- # Any of these being set is a reasonably reliable indicator that we are
- # executing in a CI environment.
- ENV_INDICATORS = [
- "CI",
- "CI_NAME",
- "CONTINUOUS_INTEGRATION",
- "BUILD_NUMBER",
- "CI_APP_ID",
- "CI_BUILD_ID",
- "CI_BUILD_NUMBER",
- "RUN_ID",
- "TASKCLUSTER_ROOT_URL",
- ].freeze
-
- # For each CI, this env suffices to indicate that we're on _that_ CI's
- # containers. (A few of them only supply a CI_NAME variable, which is also
- # nice). And if they set "CI" but we can't tell which one they are, we also
- # want to know that - a bare "ci" without another token tells us as much.
- ENV_DESCRIPTORS = {
- "TRAVIS" => "travis",
- "CIRCLECI" => "circle",
- "CIRRUS_CI" => "cirrus",
- "DSARI" => "dsari",
- "SEMAPHORE" => "semaphore",
- "JENKINS_URL" => "jenkins",
- "BUILDKITE" => "buildkite",
- "GO_SERVER_URL" => "go",
- "GITLAB_CI" => "gitlab",
- "GITHUB_ACTIONS" => "github",
- "TASKCLUSTER_ROOT_URL" => "taskcluster",
- "CI" => "ci",
- }.freeze
-
- def self.ci?
- ENV_INDICATORS.any? {|var| ENV.include?(var) }
- end
-
- def self.ci_strings
- matching_names = ENV_DESCRIPTORS.select {|env, _| ENV[env] }.values
- matching_names << ENV["CI_NAME"].downcase if ENV["CI_NAME"]
- matching_names.reject(&:empty?).sort.uniq
- end
- end
-end
diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb
index ec498a8b94..f4688d793b 100644
--- a/lib/rubygems/command.rb
+++ b/lib/rubygems/command.rb
@@ -1,12 +1,11 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
-require_relative "vendored_optparse"
+require_relative "optparse"
require_relative "requirement"
require_relative "user_interaction"
@@ -20,7 +19,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 +93,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
@@ -190,7 +191,7 @@ class Gem::Command
"Please specify at least one gem name (e.g. gem build GEMNAME)"
end
- args.reject {|arg| arg.start_with?("-") }
+ args.select {|arg| arg !~ /^-/ }
end
##
@@ -200,15 +201,11 @@ class Gem::Command
# respectively.
def get_all_gem_names_and_versions
get_all_gem_names.map do |name|
- extract_gem_name_and_version(name)
- end
- end
-
- def extract_gem_name_and_version(name) # :nodoc:
- if /\A(.*):(#{Gem::Requirement::PATTERN_RAW})\z/ =~ name
- [$1, $2]
- else
- [name]
+ if /\A(.*):(#{Gem::Requirement::PATTERN_RAW})\z/ =~ name
+ [$1, $2]
+ else
+ [name]
+ end
end
end
@@ -226,7 +223,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 +311,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
@@ -396,21 +393,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
@@ -427,10 +425,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
##
@@ -457,7 +457,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
@@ -473,7 +473,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:
@@ -485,7 +485,7 @@ class Gem::Command
@parser.separator nil
@parser.separator " Description:"
- formatted.each_line do |line|
+ formatted.split("\n").each do |line|
@parser.separator " #{line.rstrip}"
end
end
@@ -512,8 +512,8 @@ class Gem::Command
@parser.separator nil
@parser.separator " #{title}:"
- content.each_line do |line|
- @parser.separator " #{line.rstrip}"
+ content.split(/\n/).each do |line|
+ @parser.separator " #{line}"
end
end
@@ -522,7 +522,7 @@ class Gem::Command
@parser.separator nil
@parser.separator " Summary:"
- wrap(@summary, 80 - 4).each_line do |line|
+ wrap(@summary, 80 - 4).split("\n").each do |line|
@parser.separator " #{line.strip}"
end
end
@@ -579,12 +579,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
@@ -593,12 +593,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
@@ -624,7 +624,7 @@ class Gem::Command
# :stopdoc:
- HELP = <<-HELP
+ HELP = <<-HELP.freeze
RubyGems is a package manager for Ruby.
Usage:
diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb
index 15834ce4dd..1bdbd50530 100644
--- a/lib/rubygems/command_manager.rb
+++ b/lib/rubygems/command_manager.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -44,7 +43,6 @@ class Gem::CommandManager
:contents,
:dependency,
:environment,
- :exec,
:fetch,
:generate_index,
:help,
@@ -60,7 +58,6 @@ class Gem::CommandManager
:push,
:query,
:rdoc,
- :rebuild,
:search,
:server,
:signin,
@@ -85,7 +82,7 @@ class Gem::CommandManager
# Return the authoritative instance of the command manager.
def self.instance
- @instance ||= new
+ @command_manager ||= new
end
##
@@ -100,14 +97,14 @@ class Gem::CommandManager
# Reset the authoritative instance of the command manager.
def self.reset
- @instance = nil
+ @command_manager = nil
end
##
# Register all the subcommands supported by the gem command.
def initialize
- require_relative "vendored_timeout"
+ require "timeout"
@commands = {}
BUILTIN_COMMANDS.each do |name|
@@ -142,7 +139,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
##
@@ -150,7 +147,7 @@ class Gem::CommandManager
def run(args, build_args=nil)
process_args(args, build_args)
- rescue StandardError, Gem::Timeout::Error => ex
+ rescue StandardError, Timeout::Error => ex
if ex.respond_to?(:detailed_message)
msg = ex.detailed_message(highlight: false).sub(/\A(.*?)(?: \(.+?\))/) { $1 }
else
@@ -202,7 +199,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
@@ -230,16 +227,18 @@ class Gem::CommandManager
def load_and_instantiate(command_name)
command_name = command_name.to_s
const_name = command_name.capitalize.gsub(/_(.)/) { $1.upcase } << "Command"
+ load_error = nil
begin
begin
require "rubygems/commands/#{command_name}_command"
- rescue LoadError
- # it may have been defined from a rubygems_plugin.rb file
+ rescue LoadError => e
+ 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}")
ui.backtrace e
end
@@ -248,7 +247,6 @@ class Gem::CommandManager
def invoke_command(args, build_args)
cmd_name = args.shift.downcase
cmd = find_command cmd_name
- terminate_interaction 1 unless cmd
cmd.deprecation_warning if cmd.deprecated?
cmd.invoke_with_build_args args, build_args
end
diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb
index 2ec8324141..5d6152d3b9 100644
--- a/lib/rubygems/commands/build_command.rb
+++ b/lib/rubygems/commands/build_command.rb
@@ -1,24 +1,21 @@
# frozen_string_literal: true
-
require_relative "../command"
-require_relative "../gemspec_helpers"
require_relative "../package"
require_relative "../version_option"
class Gem::Commands::BuildCommand < Gem::Command
include Gem::VersionOption
- include Gem::GemspecHelpers
def initialize
super "build", "Build a gem from a gemspec"
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
@@ -77,6 +74,17 @@ Gems can be saved to a specified filename with the output option:
private
+ def find_gemspec(glob = "*.gemspec")
+ gemspecs = Dir.glob(glob).sort
+
+ if gemspecs.size > 1
+ alert_error "Multiple gemspecs found: #{gemspecs}, please specify one"
+ terminate_interaction(1)
+ end
+
+ gemspecs.first
+ end
+
def build_gem
gemspec = resolve_gem_name
diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb
index 72dcf1dd17..17b1d11b19 100644
--- a/lib/rubygems/commands/cert_command.rb
+++ b/lib/rubygems/commands/cert_command.rb
@@ -1,12 +1,11 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../security"
class Gem::Commands::CertCommand < Gem::Command
def initialize
super "cert", "Manage RubyGems certificates and signing settings",
- add: [], remove: [], list: [], build: [], sign: []
+ :add => [], :remove => [], :list => [], :build => [], :sign => []
add_option("-a", "--add CERT",
"Add a trusted certificate.") do |cert_file, options|
@@ -136,7 +135,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 +177,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 +262,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 +291,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 fb23dd9cb4..4d1f8782b1 100644
--- a/lib/rubygems/commands/check_command.rb
+++ b/lib/rubygems/commands/check_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../version_option"
require_relative "../validator"
@@ -10,7 +9,7 @@ class Gem::Commands::CheckCommand < Gem::Command
def initialize
super "check", "Check a gem repository for added or missing files",
- alien: true, doctor: false, dry_run: false, gems: true
+ :alien => true, :doctor => false, :dry_run => false, :gems => true
add_option("-a", "--[no-]alien",
'Report "unmanaged" or rogue files in the',
@@ -41,21 +40,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 bc24aaf753..1ae84924c1 100644
--- a/lib/rubygems/commands/cleanup_command.rb
+++ b/lib/rubygems/commands/cleanup_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../dependency_list"
require_relative "../uninstaller"
@@ -8,16 +7,16 @@ class Gem::Commands::CleanupCommand < Gem::Command
def initialize
super "cleanup",
"Clean up old versions of installed gems",
- force: false, install_dir: Gem.dir,
- check_dev: true
+ :force => false, :install_dir => Gem.dir,
+ :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")
@@ -38,6 +37,8 @@ class Gem::Commands::CleanupCommand < Gem::Command
@default_gems = []
@full = nil
@gems_to_cleanup = nil
+ @original_home = nil
+ @original_path = nil
@primary_gems = nil
end
@@ -73,7 +74,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
@@ -86,13 +87,16 @@ 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
def clean_gems
+ @original_home = Gem.dir
+ @original_path = Gem.path
+
get_primary_gems
get_candidate_gems
get_gems_to_cleanup
@@ -107,15 +111,17 @@ If no gems are named all gems in GEM_HOME are cleaned.
deps.reverse_each do |spec|
uninstall_dep spec
end
+
+ Gem::Specification.reset
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
@@ -124,9 +130,11 @@ 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 : Gem.dir
+ uninstall_from = options[:user_install] ? Gem.user_dir : @original_home
gems_to_cleanup = gems_to_cleanup.select do |spec|
spec.base_dir == uninstall_from
@@ -159,8 +167,8 @@ If no gems are named all gems in GEM_HOME are cleaned.
say "Attempting to uninstall #{spec.full_name}"
uninstall_options = {
- executables: false,
- version: "= #{spec.version}",
+ :executables => false,
+ :version => "= #{spec.version}",
}
uninstall_options[:user_install] = Gem.user_dir == spec.base_dir
@@ -174,5 +182,8 @@ If no gems are named all gems in GEM_HOME are cleaned.
say "Unable to uninstall #{spec.full_name}:"
say "\t#{e.class}: #{e.message}"
end
+ ensure
+ # Restore path Gem::Uninstaller may have changed
+ Gem.use_paths @original_home, *@original_path
end
end
diff --git a/lib/rubygems/commands/contents_command.rb b/lib/rubygems/commands/contents_command.rb
index bd0cbce8ba..c5fdfca31e 100644
--- a/lib/rubygems/commands/contents_command.rb
+++ b/lib/rubygems/commands/contents_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../version_option"
@@ -8,8 +7,8 @@ class Gem::Commands::ContentsCommand < Gem::Command
def initialize
super "contents", "Display the contents of the installed gems",
- specdirs: [], lib_only: false, prefix: true,
- show_install_dir: false
+ :specdirs => [], :lib_only => false, :prefix => true,
+ :show_install_dir => false
add_version_option
@@ -92,9 +91,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, "")]
@@ -103,23 +102,16 @@ prefix or only the files that are requireable.
def files_in_default_gem(spec)
spec.files.map do |file|
- if file.start_with?("#{spec.bindir}/")
- [RbConfig::CONFIG["bindir"], file.delete_prefix("#{spec.bindir}/")]
+ case file
+ when /\A#{spec.bindir}\//
+ # $' is POSTMATCH
+ [RbConfig::CONFIG["bindir"], $']
+ when /\.so\z/
+ [RbConfig::CONFIG["archdir"], file]
else
- gem spec.name, spec.version
-
- require_path = spec.require_paths.find do |path|
- file.start_with?("#{path}/")
- end
-
- requirable_part = file.delete_prefix("#{require_path}/")
-
- resolve = $LOAD_PATH.resolve_feature_path(requirable_part)&.last
- next unless resolve
-
- [resolve.delete_suffix(requirable_part), requirable_part]
+ [RbConfig::CONFIG["rubylibdir"], file]
end
- end.compact
+ end
end
def gem_contents(name)
@@ -185,7 +177,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 9aaefae999..3f69a95e83 100644
--- a/lib/rubygems/commands/dependency_command.rb
+++ b/lib/rubygems/commands/dependency_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../local_remote_options"
require_relative "../version_option"
@@ -11,14 +10,15 @@ class Gem::Commands::DependencyCommand < Gem::Command
def initialize
super "dependency",
"Show the dependencies of an installed gem",
- version: Gem::Requirement.default, domain: :local
+ :version => Gem::Requirement.default, :domain => :local
add_version_option
add_platform_option
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 +90,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 +153,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..d95e1d0dbb 100644
--- a/lib/rubygems/commands/environment_command.rb
+++ b/lib/rubygems/commands/environment_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
class Gem::Commands::EnvironmentCommand < Gem::Command
@@ -17,7 +16,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 +107,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 +172,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
deleted file mode 100644
index 7985b0fda6..0000000000
--- a/lib/rubygems/commands/exec_command.rb
+++ /dev/null
@@ -1,244 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../command"
-require_relative "../dependency_installer"
-require_relative "../gem_runner"
-require_relative "../package"
-require_relative "../version_option"
-
-class Gem::Commands::ExecCommand < Gem::Command
- include Gem::VersionOption
-
- def initialize
- super "exec", "Run a command from a gem", {
- version: Gem::Requirement.default,
- }
-
- add_version_option
- add_prerelease_option "to be installed"
-
- add_option "-g", "--gem GEM", "run the executable from the given gem" do |value, options|
- options[:gem_name] = value
- end
-
- add_option(:"Install/Update", "--conservative",
- "Prefer the most recent installed version, ",
- "rather than the latest version overall") do |_value, options|
- options[:conservative] = true
- end
- end
-
- def arguments # :nodoc:
- "COMMAND the executable command to run"
- end
-
- def defaults_str # :nodoc:
- "--version '#{Gem::Requirement.default}'"
- end
-
- def description # :nodoc:
- <<-EOF
-The exec command handles installing (if necessary) and running an executable
-from a gem, regardless of whether that gem is currently installed.
-
-The exec command can be thought of as a shortcut to running `gem install` and
-then the executable from the installed gem.
-
-For example, `gem exec rails new .` will run `rails new .` in the current
-directory, without having to manually run `gem install rails`.
-Additionally, the exec command ensures the most recent version of the gem
-is used (unless run with `--conservative`), and that the gem is not installed
-to the same gem path as user-installed gems.
- EOF
- end
-
- def usage # :nodoc:
- "#{program_name} [options --] COMMAND [args]"
- end
-
- def execute
- check_executable
-
- print_command
- if options[:gem_name] == "gem" && options[:executable] == "gem"
- set_gem_exec_install_paths
- Gem::GemRunner.new.run options[:args]
- return
- elsif options[:conservative]
- install_if_needed
- else
- install
- activate!
- end
-
- load!
- end
-
- private
-
- def handle_options(args)
- args = add_extra_args(args)
- check_deprecated_options(args)
- @options = Marshal.load Marshal.dump @defaults # deep copy
- parser.order!(args) do |v|
- # put the non-option back at the front of the list of arguments
- args.unshift(v)
-
- # stop parsing once we hit the first non-option,
- # so you can call `gem exec rails --version` and it prints the rails
- # version rather than rubygem's
- break
- end
- @options[:args] = args
-
- options[:executable], gem_version = extract_gem_name_and_version(options[:args].shift)
- options[:gem_name] ||= options[:executable]
-
- if gem_version
- if options[:version].none?
- options[:version] = Gem::Requirement.new(gem_version)
- else
- options[:version].concat [gem_version]
- end
- end
-
- if options[:prerelease] && !options[:version].prerelease?
- if options[:version].none?
- options[:version] = Gem::Requirement.default_prerelease
- else
- options[:version].concat [Gem::Requirement.default_prerelease]
- end
- end
- end
-
- def check_executable
- if options[:executable].nil?
- raise Gem::CommandLineError,
- "Please specify an executable to run (e.g. #{program_name} COMMAND)"
- end
- end
-
- def print_command
- verbose "running #{program_name} with:\n"
- opts = options.reject {|_, v| v.nil? || Array(v).empty? }
- max_length = opts.map {|k, _| k.size }.max
- opts.each do |k, v|
- next if v.nil?
- verbose "\t#{k.to_s.rjust(max_length)}: #{v}"
- end
- verbose ""
- end
-
- def install_if_needed
- activate!
- rescue Gem::MissingSpecError
- verbose "#{Gem::Dependency.new(options[:gem_name], options[:version])} not available locally, installing from remote"
- install
- activate!
- end
-
- def set_gem_exec_install_paths
- home = Gem.dir
-
- ENV["GEM_PATH"] = ([home] + Gem.path).join(File::PATH_SEPARATOR)
- ENV["GEM_HOME"] = home
- Gem.clear_paths
- end
-
- def install
- set_gem_exec_install_paths
-
- gem_name = options[:gem_name]
- gem_version = options[:version]
-
- install_options = options.merge(
- minimal_deps: false,
- wrappers: true
- )
-
- suppress_always_install do
- dep_installer = Gem::DependencyInstaller.new install_options
-
- request_set = dep_installer.resolve_dependencies gem_name, gem_version
-
- verbose "Gems to install:"
- request_set.sorted_requests.each do |activation_request|
- verbose "\t#{activation_request.full_name}"
- end
-
- request_set.install install_options
- end
-
- Gem::Specification.reset
- rescue Gem::InstallError => e
- alert_error "Error installing #{gem_name}:\n\t#{e.message}"
- terminate_interaction 1
- rescue Gem::GemNotFoundException => e
- show_lookup_failure e.name, e.version, e.errors, false
-
- terminate_interaction 2
- rescue Gem::UnsatisfiableDependencyError => e
- show_lookup_failure e.name, e.version, e.errors, false,
- "'#{gem_name}' (#{gem_version})"
-
- terminate_interaction 2
- end
-
- def activate!
- gem(options[:gem_name], options[:version])
- Gem.finish_resolve
-
- verbose "activated #{options[:gem_name]} (#{Gem.loaded_specs[options[:gem_name]].version})"
- end
-
- def load!
- argv = ARGV.clone
- ARGV.replace options[:args]
-
- exe = executable = options[:executable]
-
- contains_executable = Gem.loaded_specs.values.select do |spec|
- spec.executables.include?(executable)
- end
-
- if contains_executable.any? {|s| s.name == executable }
- contains_executable.select! {|s| s.name == executable }
- end
-
- if contains_executable.empty?
- if (spec = Gem.loaded_specs[executable]) && (exe = spec.executable)
- contains_executable << spec
- else
- alert_error "Failed to load executable `#{executable}`," \
- " are you sure the gem `#{options[:gem_name]}` contains it?"
- terminate_interaction 1
- end
- end
-
- if contains_executable.size > 1
- alert_error "Ambiguous which gem `#{executable}` should come from: " \
- "the options are #{contains_executable.map(&:name)}, " \
- "specify one via `-g`"
- terminate_interaction 1
- end
-
- load Gem.activate_bin_path(contains_executable.first.name, exe, ">= 0.a")
- ensure
- ARGV.replace argv
- end
-
- def suppress_always_install
- name = :always_install
- cls = ::Gem::Resolver::InstallerSet
- method = cls.instance_method(name)
- cls.remove_method(name)
- cls.define_method(name) { [] }
-
- begin
- yield
- ensure
- cls.remove_method(name)
- cls.define_method(name, method)
- end
- end
-end
diff --git a/lib/rubygems/commands/fetch_command.rb b/lib/rubygems/commands/fetch_command.rb
index c524cf7922..5eb45d259c 100644
--- a/lib/rubygems/commands/fetch_command.rb
+++ b/lib/rubygems/commands/fetch_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../local_remote_options"
require_relative "../version_option"
@@ -10,8 +9,8 @@ class Gem::Commands::FetchCommand < Gem::Command
def initialize
defaults = {
- suggest_alternate: true,
- version: Gem::Requirement.default,
+ :suggest_alternate => true,
+ :version => Gem::Requirement.default,
}
super "fetch", "Download a gem and place it in the current directory", defaults
@@ -63,17 +62,6 @@ then repackaging it.
def execute
check_version
-
- exit_code = fetch_gems
-
- terminate_interaction exit_code
- end
-
- private
-
- def fetch_gems
- exit_code = 0
-
version = options[:version]
platform = Gem.platforms.last
@@ -97,13 +85,10 @@ then repackaging it.
if spec.nil?
show_lookup_failure gem_name, gem_version, errors, suppress_suggestions, options[:domain]
- exit_code |= 2
next
end
source.download spec
say "Downloaded #{spec.full_name}"
end
-
- exit_code
end
end
diff --git a/lib/rubygems/commands/generate_index_command.rb b/lib/rubygems/commands/generate_index_command.rb
index 13be92593b..bc71e60ff0 100644
--- a/lib/rubygems/commands/generate_index_command.rb
+++ b/lib/rubygems/commands/generate_index_command.rb
@@ -1,51 +1,85 @@
# frozen_string_literal: true
-
require_relative "../command"
+require_relative "../indexer"
-unless defined? Gem::Commands::GenerateIndexCommand
- class Gem::Commands::GenerateIndexCommand < Gem::Command
- module RubygemsTrampoline
- def description # :nodoc:
- <<~EOF
- The generate_index command has been moved to the rubygems-generate_index gem.
- EOF
- end
+##
+# Generates a index files for use as a gem server.
+#
+# See `gem help generate_index`
- def execute
- alert_error "Install the rubygems-generate_index gem for the generate_index command"
- end
+class Gem::Commands::GenerateIndexCommand < Gem::Command
+ def initialize
+ super "generate_index",
+ "Generates the index files for a gem server directory",
+ :directory => ".", :build_modern => true
- def invoke_with_build_args(args, build_args)
- name = "rubygems-generate_index"
- spec = begin
- Gem::Specification.find_by_name(name)
- rescue Gem::LoadError
- require "rubygems/dependency_installer"
- Gem.install(name, Gem::Requirement.default, Gem::DependencyInstaller::DEFAULT_OPTIONS).find {|s| s.name == name }
- end
-
- # remove the methods defined in this file so that the methods defined in the gem are used instead,
- # and without a method redefinition warning
- %w[description execute invoke_with_build_args].each do |method|
- RubygemsTrampoline.remove_method(method)
- end
- self.class.singleton_class.remove_method(:new)
-
- spec.activate
- Gem.load_plugin_files spec.matches_for_glob("rubygems_plugin#{Gem.suffix_pattern}")
-
- self.class.new.invoke_with_build_args(args, build_args)
- end
+ add_option "-d", "--directory=DIRNAME",
+ "repository base dir containing gems subdir" do |dir, options|
+ options[:directory] = File.expand_path dir
end
- private_constant :RubygemsTrampoline
- # remove_method(:initialize) warns, but removing new does not warn
- def self.new
- command = allocate
- command.send(:initialize, "generate_index", "Generates the index files for a gem server directory (requires rubygems-generate_index)")
- command
+ add_option "--[no-]modern",
+ "Generate indexes for RubyGems",
+ "(always true)" do |value, options|
+ options[:build_modern] = value
end
- prepend(RubygemsTrampoline)
+ deprecate_option("--modern", version: "4.0", extra_msg: "Modern indexes (specs, latest_specs, and prerelease_specs) are always generated, so this option is not needed.")
+ deprecate_option("--no-modern", version: "4.0", extra_msg: "The `--no-modern` option is currently ignored. Modern indexes (specs, latest_specs, and prerelease_specs) are always generated.")
+
+ add_option "--update",
+ "Update modern indexes with gems added",
+ "since the last update" do |value, options|
+ options[:update] = value
+ end
+ end
+
+ def defaults_str # :nodoc:
+ "--directory . --modern"
+ end
+
+ def description # :nodoc:
+ <<-EOF
+The generate_index command creates a set of indexes for serving gems
+statically. The command expects a 'gems' directory under the path given to
+the --directory option. The given directory will be the directory you serve
+as the gem repository.
+
+For `gem generate_index --directory /path/to/repo`, expose /path/to/repo via
+your HTTP server configuration (not /path/to/repo/gems).
+
+When done, it will generate a set of files like this:
+
+ gems/*.gem # .gem files you want to
+ # index
+
+ specs.<version>.gz # specs index
+ latest_specs.<version>.gz # latest specs index
+ prerelease_specs.<version>.gz # prerelease specs index
+ quick/Marshal.<version>/<gemname>.gemspec.rz # Marshal quick index file
+
+The .rz extension files are compressed with the inflate algorithm.
+The Marshal version number comes from ruby's Marshal::MAJOR_VERSION and
+Marshal::MINOR_VERSION constants. It is used to ensure compatibility.
+ EOF
+ end
+
+ def execute
+ # This is always true because it's the only way now.
+ options[:build_modern] = true
+
+ if !File.exist?(options[:directory]) ||
+ !File.directory?(options[:directory])
+ alert_error "unknown directory name #{options[:directory]}."
+ terminate_interaction 1
+ else
+ indexer = Gem::Indexer.new options.delete(:directory), options
+
+ if options[:update]
+ indexer.update_index
+ else
+ indexer.generate_index
+ end
+ end
end
end
diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb
index 1619b152e7..8bfb4458ff 100644
--- a/lib/rubygems/commands/help_command.rb
+++ b/lib/rubygems/commands/help_command.rb
@@ -1,10 +1,9 @@
# frozen_string_literal: true
-
require_relative "../command"
class Gem::Commands::HelpCommand < Gem::Command
# :stopdoc:
- EXAMPLES = <<-EOF
+ EXAMPLES = <<-EOF.freeze
Some examples of 'gem' usage.
* Install 'rake', either from local directory or remote server:
@@ -53,13 +52,13 @@ Some examples of 'gem' usage.
gem update --system
EOF
- GEM_DEPENDENCIES = <<-EOF
+ GEM_DEPENDENCIES = <<-EOF.freeze
A gem dependencies file allows installation of a consistent set of gems across
multiple environments. The RubyGems implementation is designed to be
compatible with Bundler's Gemfile format. You can see additional
documentation on the format at:
- https://bundler.io
+ http://bundler.io
RubyGems automatically looks for these gem dependencies files:
@@ -172,7 +171,7 @@ and #platforms methods:
See the bundler Gemfile manual page for a list of platforms supported in a gem
dependencies file.:
- https://bundler.io/v2.5/man/gemfile.5.html
+ http://bundler.io/v1.6/man/gemfile.5.html
Ruby Version and Engine Dependency
==================================
@@ -230,7 +229,7 @@ default. This may be overridden with the :development_group option:
EOF
- PLATFORMS = <<-'EOF'
+ PLATFORMS = <<-'EOF'.freeze
RubyGems platforms are composed of three parts, a CPU, an OS, and a
version. These values are taken from values in rbconfig.rb. You can view
your current platform by running `gem environment`.
@@ -269,7 +268,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,16 +323,16 @@ 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]
- next if command&.deprecated?
+ next if command.deprecated?
summary =
if command
@@ -343,7 +342,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 +366,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/info_command.rb b/lib/rubygems/commands/info_command.rb
index f65c639662..ced7751ff5 100644
--- a/lib/rubygems/commands/info_command.rb
+++ b/lib/rubygems/commands/info_command.rb
@@ -8,8 +8,8 @@ class Gem::Commands::InfoCommand < Gem::Command
def initialize
super "info", "Show information for the given gem",
- name: //, domain: :local, details: false, versions: true,
- installed: nil, version: Gem::Requirement.default
+ :name => //, :domain => :local, :details => false, :versions => true,
+ :installed => nil, :version => Gem::Requirement.default
add_query_options
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb
index 2888b6c55a..c04c01f258 100644
--- a/lib/rubygems/commands/install_command.rb
+++ b/lib/rubygems/commands/install_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../install_update_options"
require_relative "../dependency_installer"
@@ -23,11 +22,11 @@ class Gem::Commands::InstallCommand < Gem::Command
def initialize
defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
- format_executable: false,
- lock: true,
- suggest_alternate: true,
- version: Gem::Requirement.default,
- without_groups: [],
+ :format_executable => false,
+ :lock => true,
+ :suggest_alternate => true,
+ :version => Gem::Requirement.default,
+ :without_groups => [],
})
defaults.merge!(install_update_options)
@@ -48,7 +47,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 +135,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 +161,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 +170,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
@@ -224,6 +231,10 @@ You can use `i` command instead of `install`.
rescue Gem::InstallError => e
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
exit_code |= 1
+ rescue Gem::GemNotFoundException => e
+ show_lookup_failure e.name, e.version, e.errors, suppress_suggestions
+
+ exit_code |= 2
rescue Gem::UnsatisfiableDependencyError => e
show_lookup_failure e.name, e.version, e.errors, suppress_suggestions,
"'#{gem_name}' (#{gem_version})"
@@ -251,7 +262,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/list_command.rb b/lib/rubygems/commands/list_command.rb
index fab4b73814..011873b99c 100644
--- a/lib/rubygems/commands/list_command.rb
+++ b/lib/rubygems/commands/list_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../query_utils"
@@ -11,8 +10,8 @@ class Gem::Commands::ListCommand < Gem::Command
def initialize
super "list", "Display local gems whose name matches REGEXP",
- domain: :local, details: false, versions: true,
- installed: nil, version: Gem::Requirement.default
+ :domain => :local, :details => false, :versions => true,
+ :installed => nil, :version => Gem::Requirement.default
add_query_options
end
diff --git a/lib/rubygems/commands/lock_command.rb b/lib/rubygems/commands/lock_command.rb
index f7fd5ada16..da636492c9 100644
--- a/lib/rubygems/commands/lock_command.rb
+++ b/lib/rubygems/commands/lock_command.rb
@@ -1,11 +1,10 @@
# frozen_string_literal: true
-
require_relative "../command"
class Gem::Commands::LockCommand < Gem::Command
def initialize
super "lock", "Generate a lockdown list of gems",
- strict: false
+ :strict => false
add_option "-s", "--[no-]strict",
"fail if unable to satisfy a dependency" do |strict, options|
diff --git a/lib/rubygems/commands/mirror_command.rb b/lib/rubygems/commands/mirror_command.rb
index b91a8db12d..b633cd3d81 100644
--- a/lib/rubygems/commands/mirror_command.rb
+++ b/lib/rubygems/commands/mirror_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
unless defined? Gem::Commands::MirrorCommand
diff --git a/lib/rubygems/commands/open_command.rb b/lib/rubygems/commands/open_command.rb
index 0fe90dc8b8..d5283f72dd 100644
--- a/lib/rubygems/commands/open_command.rb
+++ b/lib/rubygems/commands/open_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../version_option"
@@ -70,7 +69,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/outdated_command.rb b/lib/rubygems/commands/outdated_command.rb
index 08a9221a26..1785194389 100644
--- a/lib/rubygems/commands/outdated_command.rb
+++ b/lib/rubygems/commands/outdated_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../local_remote_options"
require_relative "../spec_fetcher"
diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb
index 12bfe3a834..959a6186dc 100644
--- a/lib/rubygems/commands/owner_command.rb
+++ b/lib/rubygems/commands/owner_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../local_remote_options"
require_relative "../gemcutter_utilities"
@@ -39,7 +38,7 @@ permission to.
add_proxy_option
add_key_option
add_otp_option
- defaults.merge! add: [], remove: []
+ defaults.merge! :add => [], :remove => []
add_option "-a", "--add NEW_OWNER", "Add an owner by user identifier" do |value, options|
options[:add] << value
@@ -79,7 +78,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 +93,14 @@ 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
+ # ignore
+ end
end
end
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index ec791d310a..72db53ef37 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../package"
require_relative "../installer"
@@ -11,10 +10,10 @@ class Gem::Commands::PristineCommand < Gem::Command
def initialize
super "pristine",
"Restores installed gems to pristine condition from files located in the gem cache",
- version: Gem::Requirement.default,
- extensions: true,
- extensions_set: false,
- all: false
+ :version => Gem::Requirement.default,
+ :extensions => true,
+ :extensions_set => false,
+ :all => false
add_option("--all",
"Restore all installed gems to pristine",
@@ -35,11 +34,6 @@ class Gem::Commands::PristineCommand < Gem::Command
options[:extensions] = value
end
- add_option("--only-missing-extensions",
- "Only restore gems with missing extensions") do |value, options|
- options[:only_missing_extensions] = value
- end
-
add_option("--only-executables",
"Only restore executables") do |value, options|
options[:only_executables] = value
@@ -57,7 +51,7 @@ class Gem::Commands::PristineCommand < Gem::Command
end
add_option("-i", "--install-dir DIR",
- "Gem repository to get gems restored") do |value, options|
+ "Gem repository to get binstubs and plugins installed") do |value, options|
options[:install_dir] = File.expand_path(value)
end
@@ -103,29 +97,23 @@ extensions will be restored.
end
def execute
- install_dir = options[:install_dir]
-
- specification_record = install_dir ? Gem::SpecificationRecord.from_path(install_dir) : Gem::Specification.specification_record
-
specs = if options[:all]
- specification_record.map
+ Gem::Specification.map
# `--extensions` must be explicitly given to pristine only gems
# with extensions.
elsif options[:extensions_set] &&
options[:extensions] && options[:args].empty?
- specification_record.select do |spec|
+ Gem::Specification.select do |spec|
spec.extensions && !spec.extensions.empty?
end
- elsif options[:only_missing_extensions]
- specification_record.select(&:missing_extensions?)
else
get_all_gem_names.sort.map do |gem_name|
- specification_record.find_all_by_name(gem_name, options[:version]).reverse
+ 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,
@@ -134,34 +122,30 @@ extensions will be restored.
say "Restoring gems to pristine condition..."
- specs.group_by(&:full_name_with_location).values.each do |grouped_specs|
- spec = grouped_specs.find {|s| !s.default_gem? } || grouped_specs.first
-
- unless only_executables_or_plugins?
- # Default gemspecs include changes provided by ruby-core installer that
- # can't currently be pristined (inclusion of compiled extension targets in
- # the file list). So stick to resetting executables if it's a default gem.
- options[:only_executables] = true if spec.default_gem?
+ specs.each do |spec|
+ if spec.default_gem?
+ say "Skipped #{spec.full_name}, it is a default gem"
+ 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
end
end
- unless spec.extensions.empty? || options[:extensions] || only_executables_or_plugins?
- say "Skipped #{spec.full_name_with_location}, it needs to compile an extension"
+ unless spec.extensions.empty? || options[:extensions] || options[:only_executables] || options[:only_plugins]
+ say "Skipped #{spec.full_name}, it needs to compile an extension"
next
end
gem = spec.cache_file
- unless File.exist?(gem) || only_executables_or_plugins?
+ unless File.exist?(gem) || options[:only_executables] || options[:only_plugins]
require_relative "../remote_fetcher"
- say "Cached gem for #{spec.full_name_with_location} not found, attempting to fetch..."
+ say "Cached gem for #{spec.full_name} not found, attempting to fetch..."
dep = Gem::Dependency.new spec.name, spec.version
found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep
@@ -184,14 +168,15 @@ extensions will be restored.
end
bin_dir = options[:bin_dir] if options[:bin_dir]
+ install_dir = options[:install_dir] if options[:install_dir]
installer_options = {
- wrappers: true,
- force: true,
- install_dir: install_dir || spec.base_dir,
- env_shebang: env_shebang,
- build_args: spec.build_args,
- bin_dir: bin_dir,
+ :wrappers => true,
+ :force => true,
+ :install_dir => install_dir || spec.base_dir,
+ :env_shebang => env_shebang,
+ :build_args => spec.build_args,
+ :bin_dir => bin_dir,
}
if options[:only_executables]
@@ -205,13 +190,7 @@ extensions will be restored.
installer.install
end
- say "Restored #{spec.full_name_with_location}"
+ say "Restored #{spec.full_name}"
end
end
-
- private
-
- def only_executables_or_plugins?
- options[:only_executables] || options[:only_plugins]
- end
end
diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb
index 591ddc3a80..46b65f4e15 100644
--- a/lib/rubygems/commands/push_command.rb
+++ b/lib/rubygems/commands/push_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../local_remote_options"
require_relative "../gemcutter_utilities"
@@ -30,7 +29,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 +74,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 3b527974a3..c6315acf8c 100644
--- a/lib/rubygems/commands/query_command.rb
+++ b/lib/rubygems/commands/query_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../query_utils"
require_relative "../deprecate"
@@ -10,7 +9,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,10 +17,11 @@ 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
+ :domain => :local, :details => false, :versions => true,
+ :installed => nil, :version => Gem::Requirement.default
add_option("-n", "--name-matches REGEXP",
"Name of gem(s) to query on matches the",
diff --git a/lib/rubygems/commands/rdoc_command.rb b/lib/rubygems/commands/rdoc_command.rb
index 977c90b8c4..a998a9704c 100644
--- a/lib/rubygems/commands/rdoc_command.rb
+++ b/lib/rubygems/commands/rdoc_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../version_option"
require_relative "../rdoc"
@@ -10,8 +9,8 @@ class Gem::Commands::RdocCommand < Gem::Command
def initialize
super "rdoc", "Generates RDoc for pre-installed gems",
- version: Gem::Requirement.default,
- include_rdoc: false, include_ri: true, overwrite: false
+ :version => Gem::Requirement.default,
+ :include_rdoc => false, :include_ri => true, :overwrite => false
add_option("--all",
"Generate RDoc/RI documentation for all",
@@ -84,7 +83,14 @@ Use --overwrite to force rebuilding of documentation.
FileUtils.rm_rf File.join(spec.doc_dir, "rdoc")
end
- doc.generate
+ begin
+ doc.generate
+ rescue Errno::ENOENT => e
+ match = / - /.match(e.message)
+ alert_error "Unable to document #{spec.full_name}, " \
+ " #{match.post_match} is missing, skipping"
+ terminate_interaction 1 if specs.length == 1
+ end
end
end
end
diff --git a/lib/rubygems/commands/rebuild_command.rb b/lib/rubygems/commands/rebuild_command.rb
deleted file mode 100644
index 97f05ef79c..0000000000
--- a/lib/rubygems/commands/rebuild_command.rb
+++ /dev/null
@@ -1,264 +0,0 @@
-# frozen_string_literal: true
-
-require "date"
-require "digest"
-require "fileutils"
-require "tmpdir"
-require_relative "../gemspec_helpers"
-require_relative "../package"
-
-class Gem::Commands::RebuildCommand < Gem::Command
- include Gem::GemspecHelpers
-
- DATE_FORMAT = "%Y-%m-%d %H:%M:%S.%N Z"
-
- def initialize
- super "rebuild", "Attempt to reproduce a build of a gem."
-
- add_option "--diff", "If the files don't match, compare them using diffoscope." do |_value, options|
- options[:diff] = true
- end
-
- 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|
- options[:strict] = true
- end
-
- add_option "--source GEM_SOURCE", "Specify the source to download the gem from." do |value, options|
- options[:source] = value
- end
-
- add_option "--original GEM_FILE", "Specify a local file to compare against (instead of downloading it)." do |value, options|
- options[:original_gem_file] = value
- end
-
- add_option "--gemspec GEMSPEC_FILE", "Specify the name of the gemspec file." do |value, options|
- options[:gemspec_file] = value
- end
-
- add_option "-C PATH", "Run as if gem build was started in <PATH> instead of the current working directory." do |value, options|
- options[:build_path] = value
- end
- end
-
- def arguments # :nodoc:
- "GEM_NAME gem name on gem server\n" \
- "GEM_VERSION gem version you are attempting to rebuild"
- end
-
- def description # :nodoc:
- <<-EOF
-The rebuild command allows you to (attempt to) reproduce a build of a gem
-from a ruby gemspec.
-
-This command assumes the gemspec can be built with the `gem build` command.
-If you use any of `gem build`, `rake build`, or`rake release` in the
-build/release process for a gem, it is a potential candidate.
-
-You will need to match the RubyGems version used, since this is included in
-the Gem metadata.
-
-If the gem includes lockfiles (e.g. Gemfile.lock) and similar, it will
-require more effort to reproduce a build. For example, it might require
-more precisely matched versions of Ruby and/or Bundler to be used.
- EOF
- end
-
- def usage # :nodoc:
- "#{program_name} GEM_NAME GEM_VERSION"
- end
-
- def execute
- gem_name, gem_version = get_gem_name_and_version
-
- old_dir, new_dir = prep_dirs
-
- gem_filename = "#{gem_name}-#{gem_version}.gem"
- old_file = File.join(old_dir, gem_filename)
- new_file = File.join(new_dir, gem_filename)
-
- if options[:original_gem_file]
- FileUtils.copy_file(options[:original_gem_file], old_file)
- else
- download_gem(gem_name, gem_version, old_file)
- end
-
- rg_version = rubygems_version(old_file)
- unless rg_version == Gem::VERSION
- alert_error <<-EOF
-You need to use the same RubyGems version #{gem_name} v#{gem_version} was built with.
-
-#{gem_name} v#{gem_version} was built using RubyGems v#{rg_version}.
-Gem files include the version of RubyGems used to build them.
-This means in order to reproduce #{gem_filename}, you must also use RubyGems v#{rg_version}.
-
-You're using RubyGems v#{Gem::VERSION}.
-
-Please install RubyGems v#{rg_version} and try again.
- EOF
- terminate_interaction 1
- end
-
- source_date_epoch = get_timestamp(old_file).to_s
-
- if build_path = options[:build_path]
- Dir.chdir(build_path) { build_gem(gem_name, source_date_epoch, new_file) }
- else
- build_gem(gem_name, source_date_epoch, new_file)
- end
-
- compare(source_date_epoch, old_file, new_file)
- end
-
- private
-
- def sha256(file)
- Digest::SHA256.hexdigest(Gem.read_binary(file))
- end
-
- def get_timestamp(file)
- mtime = nil
- File.open(file, Gem.binary_mode) do |f|
- Gem::Package::TarReader.new(f) do |tar|
- mtime = tar.seek("metadata.gz") {|tf| tf.header.mtime }
- end
- end
-
- mtime
- end
-
- def compare(source_date_epoch, old_file, new_file)
- date = Time.at(source_date_epoch.to_i).strftime("%F %T %Z")
-
- old_hash = sha256(old_file)
- new_hash = sha256(new_file)
-
- say
- say "Built at: #{date} (#{source_date_epoch})"
- say "Original build saved to: #{old_file}"
- say "Reproduced build saved to: #{new_file}"
- say "Working directory: #{options[:build_path] || Dir.pwd}"
- say
- say "Hash comparison:"
- say " #{old_hash}\t#{old_file}"
- say " #{new_hash}\t#{new_file}"
- say
-
- if old_hash == new_hash
- say "SUCCESS - original and rebuild hashes matched"
- else
- say "FAILURE - original and rebuild hashes did not match"
- say
-
- if options[:diff]
- if system("diffoscope", old_file, new_file).nil?
- alert_error "error: could not find `diffoscope` executable"
- end
- else
- say "Pass --diff for more details (requires diffoscope to be installed)."
- end
-
- terminate_interaction 1
- end
- end
-
- def prep_dirs
- rebuild_dir = Dir.mktmpdir("gem_rebuild")
- old_dir = File.join(rebuild_dir, "old")
- new_dir = File.join(rebuild_dir, "new")
-
- FileUtils.mkdir_p(old_dir)
- FileUtils.mkdir_p(new_dir)
-
- [old_dir, new_dir]
- end
-
- def get_gem_name_and_version
- args = options[:args] || []
- if args.length == 2
- gem_name, gem_version = args
- elsif args.length > 2
- raise Gem::CommandLineError, "Too many arguments"
- else
- raise Gem::CommandLineError, "Expected GEM_NAME and GEM_VERSION arguments (gem rebuild GEM_NAME GEM_VERSION)"
- end
-
- [gem_name, gem_version]
- end
-
- def build_gem(gem_name, source_date_epoch, output_file)
- gemspec = options[:gemspec_file] || find_gemspec("#{gem_name}.gemspec")
-
- if gemspec
- build_package(gemspec, source_date_epoch, output_file)
- else
- alert_error error_message(gem_name)
- terminate_interaction(1)
- end
- end
-
- def build_package(gemspec, source_date_epoch, output_file)
- with_source_date_epoch(source_date_epoch) do
- spec = Gem::Specification.load(gemspec)
- if spec
- Gem::Package.build(
- spec,
- options[:force],
- options[:strict],
- output_file
- )
- else
- alert_error "Error loading gemspec. Aborting."
- terminate_interaction 1
- end
- end
- end
-
- def with_source_date_epoch(source_date_epoch)
- old_sde = ENV["SOURCE_DATE_EPOCH"]
- ENV["SOURCE_DATE_EPOCH"] = source_date_epoch.to_s
-
- yield
- ensure
- ENV["SOURCE_DATE_EPOCH"] = old_sde
- end
-
- def error_message(gem_name)
- if gem_name
- "Couldn't find a gemspec file matching '#{gem_name}' in #{Dir.pwd}"
- else
- "Couldn't find a gemspec file in #{Dir.pwd}"
- end
- end
-
- def download_gem(gem_name, gem_version, old_file)
- # This code was based loosely off the `gem fetch` command.
- version = "= #{gem_version}"
- dep = Gem::Dependency.new gem_name, version
-
- specs_and_sources, errors =
- Gem::SpecFetcher.fetcher.spec_for_dependency dep
-
- # There should never be more than one item in specs_and_sources,
- # since we search for an exact version.
- spec, source = specs_and_sources[0]
-
- if spec.nil?
- show_lookup_failure gem_name, version, errors, options[:domain]
- terminate_interaction 1
- end
-
- download_path = source.download spec
-
- FileUtils.move(download_path, old_file)
-
- say "Downloaded #{gem_name} version #{gem_version} as #{old_file}."
- end
-
- def rubygems_version(gem_file)
- Gem::Package.new(gem_file).spec.rubygems_version
- end
-end
diff --git a/lib/rubygems/commands/search_command.rb b/lib/rubygems/commands/search_command.rb
index 50e161ac9b..3f8f7e13f2 100644
--- a/lib/rubygems/commands/search_command.rb
+++ b/lib/rubygems/commands/search_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../query_utils"
@@ -8,8 +7,8 @@ class Gem::Commands::SearchCommand < Gem::Command
def initialize
super "search", "Display remote gems whose name matches REGEXP",
- domain: :remote, details: false, versions: true,
- installed: nil, version: Gem::Requirement.default
+ :domain => :remote, :details => false, :versions => true,
+ :installed => nil, :version => Gem::Requirement.default
add_query_options
end
diff --git a/lib/rubygems/commands/server_command.rb b/lib/rubygems/commands/server_command.rb
index f1dde4aa02..56be07c79d 100644
--- a/lib/rubygems/commands/server_command.rb
+++ b/lib/rubygems/commands/server_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
unless defined? Gem::Commands::ServerCommand
diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb
index 128348b6fe..c779b7c244 100644
--- a/lib/rubygems/commands/setup_command.rb
+++ b/lib/rubygems/commands/setup_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
##
@@ -7,19 +6,19 @@ 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*$}
- VERSION_MATCHER = %r{^#\s*([\d.a-zA-Z]+)\s*/\s*\d{4}-\d{2}-\d{2}\s*$}
+ 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
def initialize
super "setup", "Install RubyGems",
- format_executable: false, document: %w[ri],
- force: true,
- site_or_vendor: "sitelibdir",
- destdir: "", prefix: "", previous_version: "",
- regenerate_binstubs: true,
- regenerate_plugins: true
+ :format_executable => false, :document => %w[ri],
+ :force => true,
+ :site_or_vendor => "sitelibdir",
+ :destdir => "", :prefix => "", :previous_version => "",
+ :regenerate_binstubs => true,
+ :regenerate_plugins => true
add_option "--previous-version=VERSION",
"Previous version of RubyGems",
@@ -55,9 +54,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 +133,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,9 +242,9 @@ 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 = { "gem" => "bin" }
executables.each do |tool, path|
say "Installing #{tool} executable" if @verbose
@@ -265,7 +264,7 @@ By default, this RubyGems will install gem as:
fp.puts bin.join
end
- install bin_tmp_file, dest_file, mode: prog_mode
+ install bin_tmp_file, dest_file, :mode => prog_mode
bin_file_names << dest_file
ensure
rm bin_tmp_file
@@ -287,7 +286,7 @@ By default, this RubyGems will install gem as:
TEXT
end
- install bin_cmd_file, "#{dest_file}.bat", mode: prog_mode
+ install bin_cmd_file, "#{dest_file}.bat", :mode => prog_mode
ensure
rm bin_cmd_file
end
@@ -340,8 +339,6 @@ By default, this RubyGems will install gem as:
require_relative "../rdoc"
- return false unless defined?(Gem::RDoc)
-
fake_spec = Gem::Specification.new "rubygems", Gem::VERSION
def fake_spec.full_gem_path
File.expand_path "../../..", __dir__
@@ -359,7 +356,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)
@@ -371,21 +368,18 @@ 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
- new_bundler_spec = Dir.chdir("bundler") { Gem::Specification.load("bundler.gemspec") }
- full_name = new_bundler_spec.full_name
- gemspec_path = "#{full_name}.gemspec"
-
- default_spec_path = File.join(specs_dir, gemspec_path)
- Gem.write_binary(default_spec_path, new_bundler_spec.to_ruby)
+ bundler_spec = Dir.chdir("bundler") { Gem::Specification.load("bundler.gemspec") }
+ default_spec_path = File.join(specs_dir, "#{bundler_spec.full_name}.gemspec")
+ Gem.write_binary(default_spec_path, bundler_spec.to_ruby)
bundler_spec = Gem::Specification.load(default_spec_path)
# Remove gemspec that was same version of vendored bundler.
- normal_gemspec = File.join(default_dir, "specifications", gemspec_path)
+ normal_gemspec = File.join(default_dir, "specifications", "bundler-#{bundler_spec.version}.gemspec")
if File.file? normal_gemspec
File.delete normal_gemspec
end
@@ -393,14 +387,20 @@ By default, this RubyGems will install gem as:
# Remove gem files that were same version of vendored bundler.
if File.directory? bundler_spec.gems_dir
Dir.entries(bundler_spec.gems_dir).
- select {|default_gem| File.basename(default_gem) == full_name }.
+ select {|default_gem| File.basename(default_gem) == "bundler-#{bundler_spec.version}" }.
each {|default_gem| rm_r File.join(bundler_spec.gems_dir, default_gem) }
end
+ bundler_bin_dir = bundler_spec.bin_dir
+ 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
+
require_relative "../installer"
Dir.chdir("bundler") do
- built_gem = Gem::Package.build(new_bundler_spec)
+ built_gem = Gem::Package.build(bundler_spec)
begin
Gem::Installer.at(
built_gem,
@@ -417,9 +417,9 @@ By default, this RubyGems will install gem as:
end
end
- new_bundler_spec.executables.each {|executable| bin_file_names << target_bin_path(bin_dir, executable) }
+ bundler_spec.executables.each {|executable| bin_file_names << target_bin_path(bin_dir, executable) }
- say "Bundler #{new_bundler_spec.version} installed"
+ say "Bundler #{bundler_spec.version} installed"
end
def make_destination_dirs
@@ -429,10 +429,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
@@ -575,8 +575,8 @@ abort "#{deprecation_message}"
def uninstall_old_gemcutter
require_relative "../uninstaller"
- ui = Gem::Uninstaller.new("gemcutter", all: true, ignore: true,
- version: "< 0.4")
+ ui = Gem::Uninstaller.new("gemcutter", :all => true, :ignore => true,
+ :version => "< 0.4")
ui.uninstall
rescue Gem::InstallError
end
@@ -587,8 +587,6 @@ abort "#{deprecation_message}"
args = %w[--all --only-executables --silent]
args << "--bindir=#{bindir}"
- args << "--install-dir=#{default_dir}"
-
if options[:env_shebang]
args << "--env-shebang"
end
@@ -640,10 +638,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/signin_command.rb b/lib/rubygems/commands/signin_command.rb
index 0f77908c5b..2660eee4f3 100644
--- a/lib/rubygems/commands/signin_command.rb
+++ b/lib/rubygems/commands/signin_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../gemcutter_utilities"
diff --git a/lib/rubygems/commands/signout_command.rb b/lib/rubygems/commands/signout_command.rb
index bdd01e4393..fa688ea3f8 100644
--- a/lib/rubygems/commands/signout_command.rb
+++ b/lib/rubygems/commands/signout_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
class Gem::Commands::SignoutCommand < Gem::Command
diff --git a/lib/rubygems/commands/sources_command.rb b/lib/rubygems/commands/sources_command.rb
index 976f4a4ea2..5a8f5af9c3 100644
--- a/lib/rubygems/commands/sources_command.rb
+++ b/lib/rubygems/commands/sources_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../remote_fetcher"
require_relative "../spec_fetcher"
@@ -59,7 +58,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
say "#{source_uri} added to sources"
end
- rescue Gem::URI::Error, ArgumentError
+ rescue URI::Error, ArgumentError
say "#{source_uri} is not a URI"
terminate_interaction 1
rescue Gem::RemoteFetcher::FetchError => e
@@ -71,7 +70,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
@@ -81,10 +80,10 @@ Do you want to add this source?
end
def check_rubygems_https(source_uri) # :nodoc:
- uri = Gem::URI source_uri
+ 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 +98,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 +193,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 a21ed35be3..12004a6d56 100644
--- a/lib/rubygems/commands/specification_command.rb
+++ b/lib/rubygems/commands/specification_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../local_remote_options"
require_relative "../version_option"
@@ -13,27 +12,27 @@ class Gem::Commands::SpecificationCommand < Gem::Command
Gem.load_yaml
super "specification", "Display gem specification (in yaml)",
- domain: :local, version: Gem::Requirement.default,
- format: :yaml
+ :domain => :local, :version => Gem::Requirement.default,
+ :format => :yaml
add_version_option("examine")
add_platform_option
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 +106,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 +133,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..0246f42e3e 100644
--- a/lib/rubygems/commands/stale_command.rb
+++ b/lib/rubygems/commands/stale_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
class Gem::Commands::StaleCommand < Gem::Command
@@ -18,7 +17,7 @@ longer using.
end
def usage # :nodoc:
- program_name.to_s
+ "#{program_name}"
end
def execute
@@ -34,7 +33,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 3d6e41e49e..3c520826e5 100644
--- a/lib/rubygems/commands/uninstall_command.rb
+++ b/lib/rubygems/commands/uninstall_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../version_option"
require_relative "../uninstaller"
@@ -15,11 +14,12 @@ class Gem::Commands::UninstallCommand < Gem::Command
def initialize
super "uninstall", "Uninstall gems from the local repository",
- version: Gem::Requirement.default, user_install: true,
- check_dev: false, vendor: false
+ :version => Gem::Requirement.default, :user_install => true,
+ :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 +79,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 +95,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
@@ -125,9 +125,6 @@ that is a dependency of an existing gem. You can use the
def execute
check_version
- # Consider only gem specifications installed at `--install-dir`
- Gem::Specification.dirs = options[:install_dir] if options[:install_dir]
-
if options[:all] && !options[:args].empty?
uninstall_specific
elsif options[:all]
@@ -138,7 +135,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
@@ -157,14 +154,9 @@ that is a dependency of an existing gem. You can use the
gem_specs = Gem::Specification.find_all_by_name(name, original_gem_version[name])
- if gem_specs.empty?
- say("Gem '#{name}' is not installed")
- else
- gem_specs.reject!(&:default_gem?) if gem_specs.size > 1
-
- gem_specs.each do |spec|
- deplist.add spec
- end
+ say("Gem '#{name}' is not installed") if gem_specs.empty?
+ gem_specs.each do |spec|
+ deplist.add spec
end
end
@@ -173,14 +165,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
@@ -188,12 +181,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" \
- "\tgem uninstall #{spec.name} --install-dir=#{spec.base_dir}")
+ 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 f25c045c62..b1f939b0bc 100644
--- a/lib/rubygems/commands/unpack_command.rb
+++ b/lib/rubygems/commands/unpack_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../version_option"
require_relative "../security_option"
@@ -21,15 +20,15 @@ class Gem::Commands::UnpackCommand < Gem::Command
require "fileutils"
super "unpack", "Unpack an installed gem to the current directory",
- version: Gem::Requirement.default,
- target: Dir.pwd
+ :version => Gem::Requirement.default,
+ :target => Dir.pwd
add_option("--target=DIR",
"target directory for unpacking") do |value, options|
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 +95,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 +131,7 @@ command help for an example.
return this_path if File.exist? this_path
end
- nil
+ return nil
end
##
@@ -151,16 +152,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 8e80d46856..5c90981645 100644
--- a/lib/rubygems/commands/update_command.rb
+++ b/lib/rubygems/commands/update_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../command_manager"
require_relative "../dependency_installer"
@@ -21,7 +20,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
def initialize
options = {
- force: false,
+ :force => false,
}
options.merge!(install_update_options)
@@ -37,10 +36,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 +119,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 +127,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 +185,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
@@ -197,17 +194,18 @@ command to remove old versions.
yield
else
require "tmpdir"
- Dir.mktmpdir("gem_update") do |tmpdir|
- FileUtils.mv Gem.plugindir, tmpdir
+ tmpdir = Dir.mktmpdir
+ FileUtils.mv Gem.plugindir, tmpdir
- status = yield
+ status = yield
- unless status
- FileUtils.mv File.join(tmpdir, "plugins"), Gem.plugindir
- end
-
- status
+ if status
+ FileUtils.rm_rf tmpdir
+ else
+ FileUtils.mv File.join(tmpdir, "plugins"), Gem.plugindir
end
+
+ status
end
end
@@ -232,7 +230,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)
@@ -243,7 +241,7 @@ command to remove old versions.
@installer = Gem::DependencyInstaller.new update_options
- say "Updating #{name}" unless options[:system]
+ say "Updating #{name}" unless options[:system] && options[:silent]
begin
@installer.install name, Gem::Requirement.new(version)
rescue Gem::InstallError, Gem::DependencyError => e
@@ -281,7 +279,7 @@ command to remove old versions.
check_oldest_rubygems version
installed_gems = Gem::Specification.find_all_by_name "rubygems-update", requirement
- installed_gems = update_gem("rubygems-update", requirement) if installed_gems.empty? || installed_gems.first.version != version
+ installed_gems = update_gem("rubygems-update", version) if installed_gems.empty? || installed_gems.first.version != version
return if installed_gems.empty?
install_rubygems installed_gems.first
@@ -293,14 +291,16 @@ command to remove old versions.
args << "--prefix" << Gem.prefix if Gem.prefix
args << "--no-document" unless options[:document].include?("rdoc") || options[:document].include?("ri")
args << "--no-format-executable" if options[:no_format_executable]
- args << "--previous-version" << Gem::VERSION
+ args << "--previous-version" << Gem::VERSION if
+ options[:system] == true ||
+ Gem::Version.new(options[:system]) >= Gem::Version.new(2)
args
end
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 }
@@ -325,8 +325,12 @@ command to remove old versions.
@oldest_supported_version ||=
if Gem.ruby_version > Gem::Version.new("3.1.a")
Gem::Version.new("3.3.3")
- else
+ elsif Gem.ruby_version > Gem::Version.new("3.0.a")
Gem::Version.new("3.2.3")
+ elsif Gem.ruby_version > Gem::Version.new("2.7.a")
+ Gem::Version.new("3.1.2")
+ else
+ Gem::Version.new("3.0.1")
end
end
end
diff --git a/lib/rubygems/commands/which_command.rb b/lib/rubygems/commands/which_command.rb
index 5ed4d9d142..5b9a79b734 100644
--- a/lib/rubygems/commands/which_command.rb
+++ b/lib/rubygems/commands/which_command.rb
@@ -1,11 +1,10 @@
# frozen_string_literal: true
-
require_relative "../command"
class Gem::Commands::WhichCommand < Gem::Command
def initialize
super "which", "Find the location of a library file you can require",
- search_gems_first: false, show_all: false
+ :search_gems_first => false, :show_all => false
add_option "-a", "--[no-]all", "show all matching files" do |show_all, options|
options[:show_all] = show_all
diff --git a/lib/rubygems/commands/yank_command.rb b/lib/rubygems/commands/yank_command.rb
index fbdc262549..1499f72f5d 100644
--- a/lib/rubygems/commands/yank_command.rb
+++ b/lib/rubygems/commands/yank_command.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../command"
require_relative "../local_remote_options"
require_relative "../version_option"
@@ -62,7 +61,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 +88,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 1cd38977da..4aa8b4d33a 100644
--- a/lib/rubygems/config_file.rb
+++ b/lib/rubygems/config_file.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -188,10 +187,10 @@ class Gem::ConfigFile
operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS)
platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS)
system_config = load_file SYSTEM_WIDE_CONFIG_FILE
- user_config = load_file config_file_name
+ 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,33 +201,21 @@ class Gem::ConfigFile
@hash = @hash.merge environment_config
end
- @hash.transform_keys! do |k|
- # gemhome and gempath are not working with symbol keys
- if %w[backtrace bulk_threshold verbose update_sources cert_expiration_length_days
- install_extension_in_lib ipv4_fallback_enabled sources disable_default_gem_server
- ssl_verify_mode ssl_ca_cert ssl_client_cert].include?(k)
- k.to_sym
- else
- k
- end
- 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
- @verbose = @hash[:verbose] if @hash.key? :verbose
+ @home = @hash[:gemhome] if @hash.key? :gemhome
+ @path = @hash[:gempath] if @hash.key? :gempath
@update_sources = @hash[:update_sources] if @hash.key? :update_sources
- # TODO: We should handle concurrent_downloads same as other options
+ @verbose = @hash[:verbose] if @hash.key? :verbose
+ @disable_default_gem_server = @hash[:disable_default_gem_server] if @hash.key? :disable_default_gem_server
+ @sources = @hash[:sources] if @hash.key? :sources
@cert_expiration_length_days = @hash[:cert_expiration_length_days] if @hash.key? :cert_expiration_length_days
@ipv4_fallback_enabled = @hash[:ipv4_fallback_enabled] if @hash.key? :ipv4_fallback_enabled
- @home = @hash[:gemhome] if @hash.key? :gemhome
- @path = @hash[:gempath] if @hash.key? :gempath
- @sources = @hash[:sources] if @hash.key? :sources
- @disable_default_gem_server = @hash[:disable_default_gem_server] if @hash.key? :disable_default_gem_server
- @ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode
- @ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert
- @ssl_client_cert = @hash[:ssl_client_cert] if @hash.key? :ssl_client_cert
+ @ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode
+ @ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert
+ @ssl_client_cert = @hash[:ssl_client_cert] if @hash.key? :ssl_client_cert
@api_keys = nil
@rubygems_api_key = nil
@@ -253,9 +240,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:
@@ -336,9 +323,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
@@ -354,18 +343,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
@@ -485,17 +476,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.
@@ -510,12 +501,12 @@ if you believe they were disclosed to a third party.
# Return the configuration information for +key+.
def [](key)
- @hash[key] || @hash[key.to_s]
+ @hash[key.to_s]
end
# Set configuration option +key+ to +value+.
def []=(key, value)
- @hash[key] = value
+ @hash[key.to_s] = value
end
def ==(other) # :nodoc:
@@ -530,64 +521,8 @@ 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)
- deep_transform_config_keys!(content)
- end
-
private
- def self.deep_transform_config_keys!(config)
- config.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
-
- config.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.empty?
- nil
- elsif v.is_a?(Hash)
- deep_transform_config_keys!(v)
- else
- v
- end
- end
-
- config
- end
-
def set_config_file_name(args)
@config_file_name = ENV["GEMRC"]
need_config_file_name = false
@@ -598,7 +533,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 073966b696..6dcc4a06e4 100644
--- a/lib/rubygems/core_ext/kernel_require.rb
+++ b/lib/rubygems/core_ext/kernel_require.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -9,12 +8,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,45 +36,56 @@ 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)
-
- # If +path+ belongs to a default gem, we activate it and then go straight
- # to normal require
-
- if spec = Gem.find_default_spec(path)
- name = spec.name
+ begin
+ if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?)
+ monitor_owned = RUBYGEMS_ACTIVATION_MONITOR.mon_owned?
+ end
+ RUBYGEMS_ACTIVATION_MONITOR.enter
- next if Gem.loaded_specs[name]
+ 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|
- if File.symlink? lp # for backward compatibility
- next
+ Gem.suffixes.each do |s|
+ $LOAD_PATH[0...load_path_check_index].each do |lp|
+ safe_lp = lp.dup.tap(&Gem::UNTAINT)
+ 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(lp, "#{path}#{s}"))
- rp = full_path if File.file?(full_path)
+ full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}"))
+ if File.file?(full_path)
+ rp = full_path
+ break
+ end
end
+ break if rp
end
rp
end
- Kernel.send(:gem, name, Gem::Requirement.default_prerelease) unless
- resolved_path
-
- next
+ 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
@@ -84,7 +95,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...
@@ -104,7 +116,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.
@@ -115,7 +129,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
@@ -125,25 +140,39 @@ 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
+ ensure
+ if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?)
+ if monitor_owned != (ow = RUBYGEMS_ACTIVATION_MONITOR.mon_owned?)
+ STDERR.puts [$$, Thread.current, $!, $!.backtrace].inspect if $!
+ raise "CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before #{monitor_owned} -> after #{ow}"
+ end
+ end
end
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..c9e0a92953 100644
--- a/lib/rubygems/core_ext/tcpsocket_init.rb
+++ b/lib/rubygems/core_ext/tcpsocket_init.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require "socket"
module CoreExtensions
@@ -19,7 +17,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 ca161a4d95..8daff0bc30 100644
--- a/lib/rubygems/defaults.rb
+++ b/lib/rubygems/defaults.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
-
module Gem
- DEFAULT_HOST = "https://rubygems.org"
+ DEFAULT_HOST = "https://rubygems.org".freeze
@post_install_hooks ||= []
@done_installing_hooks ||= []
@@ -24,7 +23,7 @@ module Gem
default_spec_cache_dir = File.join Gem.user_home, ".gem", "specs"
unless File.exist?(default_spec_cache_dir)
- default_spec_cache_dir = File.join Gem.cache_home, "gem", "specs"
+ default_spec_cache_dir = File.join Gem.data_home, "gem", "specs"
end
default_spec_cache_dir
@@ -80,7 +79,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
@@ -94,7 +93,7 @@ module Gem
# The home directory for the user.
def self.user_home
- @user_home ||= find_home
+ @user_home ||= find_home.tap(&Gem::UNTAINT)
end
##
@@ -112,7 +111,7 @@ module Gem
# The path to standard location of the user's configuration directory.
def self.config_home
- @config_home ||= ENV["XDG_CONFIG_HOME"] || File.join(Gem.user_home, ".config")
+ @config_home ||= (ENV["XDG_CONFIG_HOME"] || File.join(Gem.user_home, ".config"))
end
##
@@ -131,35 +130,35 @@ module Gem
# The path to standard location of the user's .gemrc file.
def self.config_file
- @config_file ||= find_config_file
+ @config_file ||= find_config_file.tap(&Gem::UNTAINT)
end
##
# The path to standard location of the user's state file.
def self.state_file
- @state_file ||= File.join(Gem.state_home, "gem", "last_update_check")
+ @state_file ||= File.join(Gem.state_home, "gem", "last_update_check").tap(&Gem::UNTAINT)
end
##
# The path to standard location of the user's cache directory.
def self.cache_home
- @cache_home ||= ENV["XDG_CACHE_HOME"] || File.join(Gem.user_home, ".cache")
+ @cache_home ||= (ENV["XDG_CACHE_HOME"] || File.join(Gem.user_home, ".cache"))
end
##
# The path to standard location of the user's data directory.
def self.data_home
- @data_home ||= ENV["XDG_DATA_HOME"] || File.join(Gem.user_home, ".local", "share")
+ @data_home ||= (ENV["XDG_DATA_HOME"] || File.join(Gem.user_home, ".local", "share"))
end
##
# The path to standard location of the user's state directory.
def self.state_home
- @state_home ||= ENV["XDG_STATE_HOME"] || File.join(Gem.user_home, ".local", "state")
+ @data_home ||= (ENV["XDG_STATE_HOME"] || File.join(Gem.user_home, ".local", "state"))
end
##
@@ -184,11 +183,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,
@@ -236,18 +231,6 @@ module Gem
end
##
- # Enables automatic installation into user directory
-
- def self.default_user_install # :nodoc:
- if !ENV.key?("GEM_HOME") && (File.exist?(Gem.dir) && !File.writable?(Gem.dir))
- Gem.ui.say "Defaulting to user installation because default installation directory (#{Gem.dir}) is not writable."
- return true
- end
-
- false
- end
-
- ##
# Install extensions into lib as well as into the extension directory.
def self.install_extension_in_lib # :nodoc:
diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb
index d1ec9222af..7fa0f91bd4 100644
--- a/lib/rubygems/dependency.rb
+++ b/lib/rubygems/dependency.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The Dependency class holds a Gem name and a Gem::Requirement.
@@ -46,10 +45,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 +73,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 +168,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 +204,7 @@ class Gem::Dependency
requirement.satisfied_by? version
end
- alias_method :===, :=~
+ alias === =~
##
# :call-seq:
@@ -261,7 +262,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
@@ -271,7 +272,15 @@ class Gem::Dependency
end
def matching_specs(platform_only = false)
- matches = Gem::Specification.find_all_by_name(name, requirement)
+ env_req = Gem.env_requirement(name)
+ matches = Gem::Specification.stubs_for(name).find_all do |spec|
+ requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
+ end.map(&:to_spec)
+
+ if prioritizes_bundler?
+ require_relative "bundler_version_finder"
+ Gem::BundlerVersionFinder.prioritize!(matches)
+ end
if platform_only
matches.reject! do |spec|
@@ -279,7 +288,7 @@ class Gem::Dependency
end
end
- matches.reject(&:ignored?)
+ matches
end
##
@@ -289,6 +298,10 @@ class Gem::Dependency
@requirement.specific?
end
+ def prioritizes_bundler?
+ name == "bundler".freeze && !specific?
+ end
+
def to_specs
matches = matching_specs true
@@ -310,15 +323,15 @@ 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?
- # Consider prereleases only as a fallback
+ # Move prereleases to the end of the list for >= 0 requirements
pre, matches = matches.partition {|spec| spec.version.prerelease? }
- matches = pre if matches.empty?
+ matches += pre if requirement == Gem::Requirement.default
end
matches.first
@@ -337,12 +350,4 @@ class Gem::Dependency
:released
end
end
-
- def encode_with(coder) # :nodoc:
- coder.add "name", @name
- coder.add "requirement", @requirement
- coder.add "type", @type
- coder.add "prerelease", @prerelease
- coder.add "version_requirements", @version_requirements
- end
end
diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb
index b119dca1cf..1009376b90 100644
--- a/lib/rubygems/dependency_installer.rb
+++ b/lib/rubygems/dependency_installer.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../rubygems"
require_relative "dependency_list"
require_relative "package"
@@ -17,18 +16,18 @@ class Gem::DependencyInstaller
extend Gem::Deprecate
DEFAULT_OPTIONS = { # :nodoc:
- env_shebang: false,
- document: %w[ri],
- domain: :both, # HACK: dup
- force: false,
- format_executable: false, # HACK: dup
- ignore_dependencies: false,
- prerelease: false,
- security_policy: nil, # HACK: NoSecurity requires OpenSSL. AlmostNo? Low?
- wrappers: true,
- build_args: nil,
- build_docs_in_background: false,
- install_as_default: false,
+ :env_shebang => false,
+ :document => %w[ri],
+ :domain => :both, # HACK dup
+ :force => false,
+ :format_executable => false, # HACK dup
+ :ignore_dependencies => false,
+ :prerelease => false,
+ :security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low?
+ :wrappers => true,
+ :build_args => nil,
+ :build_docs_in_background => false,
+ :install_as_default => false,
}.freeze
##
@@ -66,7 +65,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 +162,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 +178,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
@@ -228,22 +230,22 @@ class Gem::DependencyInstaller
@installed_gems = []
options = {
- bin_dir: @bin_dir,
- build_args: @build_args,
- document: @document,
- env_shebang: @env_shebang,
- force: @force,
- format_executable: @format_executable,
- ignore_dependencies: @ignore_dependencies,
- prerelease: @prerelease,
- security_policy: @security_policy,
- user_install: @user_install,
- wrappers: @wrappers,
- build_root: @build_root,
- install_as_default: @install_as_default,
- dir_mode: @dir_mode,
- data_mode: @data_mode,
- prog_mode: @prog_mode,
+ :bin_dir => @bin_dir,
+ :build_args => @build_args,
+ :document => @document,
+ :env_shebang => @env_shebang,
+ :force => @force,
+ :format_executable => @format_executable,
+ :ignore_dependencies => @ignore_dependencies,
+ :prerelease => @prerelease,
+ :security_policy => @security_policy,
+ :user_install => @user_install,
+ :wrappers => @wrappers,
+ :build_root => @build_root,
+ :install_as_default => @install_as_default,
+ :dir_mode => @dir_mode,
+ :data_mode => @data_mode,
+ :prog_mode => @prog_mode,
}
options[:install_dir] = @install_dir if @only_install_dir
@@ -291,11 +293,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 ad5e59e8c1..eaf6702177 100644
--- a/lib/rubygems/dependency_list.rb
+++ b/lib/rubygems/dependency_list.rb
@@ -1,12 +1,11 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
-require_relative "vendored_tsort"
+require_relative "tsort"
require_relative "deprecate"
##
@@ -105,7 +104,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 7d24f9cbfc..5fe0afb6b0 100644
--- a/lib/rubygems/deprecate.rb
+++ b/lib/rubygems/deprecate.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Provides 3 methods for declaring when something is going away.
#
@@ -69,101 +68,97 @@
# end
# end
-module Gem
- module Deprecate
- def self.skip # :nodoc:
- @skip ||= false
- end
+module Gem::Deprecate
- def self.skip=(v) # :nodoc:
- @skip = v
- end
+ def self.skip # :nodoc:
+ @skip ||= false
+ end
- ##
- # Temporarily turn off warnings. Intended for tests only.
+ def self.skip=(v) # :nodoc:
+ @skip = v
+ end
- def skip_during
- original = Gem::Deprecate.skip
- Gem::Deprecate.skip = true
- yield
- ensure
- Gem::Deprecate.skip = original
- end
+ ##
+ # Temporarily turn off warnings. Intended for tests only.
- def self.next_rubygems_major_version # :nodoc:
- Gem::Version.new(Gem.rubygems_version.segments.first).bump
- end
+ def skip_during
+ Gem::Deprecate.skip, original = true, Gem::Deprecate.skip
+ yield
+ ensure
+ Gem::Deprecate.skip = original
+ end
- ##
- # Simple deprecation method that deprecates +name+ by wrapping it up
- # in a dummy method. It warns on each call to the dummy method
- # telling the user of +repl+ (unless +repl+ is :none) and the
- # year/month that it is planned to go away.
+ def self.next_rubygems_major_version # :nodoc:
+ Gem::Version.new(Gem.rubygems_version.segments.first).bump
+ end
+
+ ##
+ # Simple deprecation method that deprecates +name+ by wrapping it up
+ # in a dummy method. It warns on each call to the dummy method
+ # telling the user of +repl+ (unless +repl+ is :none) and the
+ # year/month that it is planned to go away.
- def deprecate(name, repl, year, month)
- class_eval do
- old = "_deprecated_#{name}"
- alias_method old, name
- define_method name do |*args, &block|
- klass = is_a? 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(":")}",
- ]
- warn "#{msg.join}." unless Gem::Deprecate.skip
- send old, *args, &block
- end
- ruby2_keywords name if respond_to?(:ruby2_keywords, true)
+ def deprecate(name, repl, year, month)
+ class_eval do
+ old = "_deprecated_#{name}"
+ alias_method old, name
+ define_method name do |*args, &block|
+ klass = self.kind_of? Module
+ target = klass ? "#{self}." : "#{self.class}#"
+ 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
end
+ ruby2_keywords name if respond_to?(:ruby2_keywords, true)
end
+ end
- ##
- # Simple deprecation method that deprecates +name+ by wrapping it up
- # in a dummy method. It warns on each call to the dummy method
- # telling the user of +repl+ (unless +repl+ is :none) and the
- # Rubygems version that it is planned to go away.
+ ##
+ # Simple deprecation method that deprecates +name+ by wrapping it up
+ # in a dummy method. It warns on each call to the dummy method
+ # telling the user of +repl+ (unless +repl+ is :none) and the
+ # Rubygems version that it is planned to go away.
- def rubygems_deprecate(name, replacement=:none)
- class_eval do
- old = "_deprecated_#{name}"
- alias_method old, name
- define_method name do |*args, &block|
- klass = is_a? 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(":")}",
- ]
- warn "#{msg.join}." unless Gem::Deprecate.skip
- send old, *args, &block
- end
- ruby2_keywords name if respond_to?(:ruby2_keywords, true)
+ def rubygems_deprecate(name, replacement=:none)
+ class_eval do
+ old = "_deprecated_#{name}"
+ alias_method old, name
+ define_method name do |*args, &block|
+ 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(":")}",
+ ]
+ warn "#{msg.join}." unless Gem::Deprecate.skip
+ send old, *args, &block
end
+ ruby2_keywords name if respond_to?(:ruby2_keywords, true)
end
+ end
- # Deprecation method to deprecate Rubygems commands
- def rubygems_deprecate_command(version = Gem::Deprecate.next_rubygems_major_version)
- class_eval do
- define_method "deprecated?" do
- true
- end
+ # Deprecation method to deprecate Rubygems commands
+ def rubygems_deprecate_command
+ class_eval do
+ define_method "deprecated?" do
+ true
+ end
- define_method "deprecation_warning" do
- msg = [
- "#{command} command is deprecated",
- ". It will be removed in Rubygems #{version}.\n",
- ]
+ define_method "deprecation_warning" do
+ msg = [ "#{self.command} command is deprecated",
+ ". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}.\n",
+ ]
- alert_warning msg.join.to_s unless Gem::Deprecate.skip
- end
+ alert_warning "#{msg.join}" unless Gem::Deprecate.skip
end
end
-
- module_function :rubygems_deprecate, :rubygems_deprecate_command, :skip_during
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..96829227fc 100644
--- a/lib/rubygems/doctor.rb
+++ b/lib/rubygems/doctor.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../rubygems"
require_relative "user_interaction"
@@ -33,7 +32,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 +52,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 +74,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 +103,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 57fb3eb120..ac82a551a5 100644
--- a/lib/rubygems/errors.rb
+++ b/lib/rubygems/errors.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# This file contains all the various exceptions and other errors that are used
# inside of RubyGems.
@@ -30,7 +29,6 @@ module Gem
@name = name
@requirement = requirement
@extra_message = extra_message
- super(message)
end
def message # :nodoc:
@@ -54,15 +52,15 @@ module Gem
attr_reader :specs
def initialize(name, requirement, specs)
- @specs = specs
super(name, requirement)
+ @specs = specs
end
private
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
@@ -135,7 +133,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
@@ -172,6 +174,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 a9b57ccade..ca4fbb20de 100644
--- a/lib/rubygems/exceptions.rb
+++ b/lib/rubygems/exceptions.rb
@@ -104,6 +104,9 @@ end
class Gem::GemNotFoundException < Gem::Exception; end
+##
+# Raised by the DependencyInstaller when a specific gem cannot be found
+
class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException
##
# Creates a new SpecificGemNotFoundException for a gem with the given +name+
@@ -134,8 +137,6 @@ class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException
attr_reader :errors
end
-Gem.deprecate_constant :SpecificGemNotFoundException
-
##
# Raised by Gem::Resolver when dependencies conflict and create the
# inability to find a valid possible spec for a request.
@@ -171,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
@@ -214,16 +214,6 @@ class Gem::RubyVersionMismatch < Gem::Exception; end
class Gem::VerificationError < Gem::Exception; end
##
-# Raised by Gem::WebauthnListener when an error occurs during security
-# device verification.
-
-class Gem::WebauthnVerificationError < Gem::Exception
- def initialize(message)
- super "Security device verification failed: #{message}"
- end
-end
-
-##
# Raised to indicate that a system exit should occur with the specified
# exit_code
@@ -231,7 +221,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+
@@ -264,7 +254,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.rb b/lib/rubygems/ext.rb
index b5ca126a08..d714985c21 100644
--- a/lib/rubygems/ext.rb
+++ b/lib/rubygems/ext.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
diff --git a/lib/rubygems/ext/build_error.rb b/lib/rubygems/ext/build_error.rb
index 0329c1eec3..727bc065c2 100644
--- a/lib/rubygems/ext/build_error.rb
+++ b/lib/rubygems/ext/build_error.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Raised when there is an error while building extensions.
diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb
index be1ba3031c..7fb8958d7f 100644
--- a/lib/rubygems/ext/builder.rb
+++ b/lib/rubygems/ext/builder.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -7,7 +6,6 @@
#++
require_relative "../user_interaction"
-require_relative "../shellwords"
class Gem::Ext::Builder
include Gem::UserInteraction
@@ -27,17 +25,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|
@@ -55,53 +55,30 @@ class Gem::Ext::Builder
end
end
- def self.ruby
- # Gem.ruby is quoted if it contains whitespace
- cmd = Shellwords.split(Gem.ruby)
-
- # This load_path is only needed when running rubygems test without a proper installation.
- # Prepending it in a normal installation will cause problem with order of $LOAD_PATH.
- # Therefore only add load_path if it is not present in the default $LOAD_PATH.
- load_path = File.expand_path("../..", __dir__)
- case load_path
- when RbConfig::CONFIG["sitelibdir"], RbConfig::CONFIG["vendorlibdir"], RbConfig::CONFIG["rubylibdir"]
- cmd
- else
- cmd << "-I#{load_path}"
- end
- end
-
def self.run(command, results, command_name = nil, dir = Dir.pwd, env = {})
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)
end
results << "current directory: #{dir}"
- results << Shellwords.join(command)
+ require "shellwords"
+ results << command.shelljoin
require "open3"
# Set $SOURCE_DATE_EPOCH for the subprocess.
build_env = { "SOURCE_DATE_EPOCH" => Gem.source_date_epoch_string }.merge(env)
output, status = begin
- Open3.popen2e(build_env, *command, chdir: dir) do |_stdin, stdouterr, wait_thread|
- output = String.new
- while line = stdouterr.gets
- output << line
- if verbose
- print line
- end
- end
- [output, wait_thread.value]
- end
- rescue StandardError => error
+ Open3.capture2e(build_env, *command, :chdir => dir)
+ rescue => error
raise Gem::InstallError, "#{command_name || class_name} failed#{error.message}"
end
- unless verbose
+ if verbose
+ puts output
+ else
results << output
end
ensure
@@ -196,7 +173,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
@@ -212,7 +189,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 f0537ab693..022aabf481 100644
--- a/lib/rubygems/ext/cargo_builder.rb
+++ b/lib/rubygems/ext/cargo_builder.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative "../shellwords"
-
# This class is used by rubygems to build Rust extensions. It is a thin-wrapper
# over the `cargo rustc` command which takes care of building Rust code in a way
# that Ruby can use.
@@ -75,6 +73,8 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
end
def cargo_command(cargo_toml, dest_path, args = [], crate_name = nil)
+ require "shellwords"
+
cmd = []
cmd += [cargo, "rustc"]
cmd += ["--crate-type", "cdylib"]
@@ -185,7 +185,6 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
end
def cargo_dylib_path(dest_path, crate_name)
- so_ext = RbConfig::CONFIG["SOEXT"]
prefix = so_ext == "dll" ? "" : "lib"
path_parts = [dest_path]
path_parts << ENV["CARGO_BUILD_TARGET"] if ENV["CARGO_BUILD_TARGET"]
@@ -199,8 +198,8 @@ 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
+ Open3.capture2e(cargo, "metadata", "--no-deps", "--format-version", "1", :chdir => cargo_dir)
+ rescue => error
raise Gem::InstallError, "cargo metadata failed #{error.message}"
end
@@ -247,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)
@@ -294,7 +293,7 @@ EOF
case var_name
# On windows, it is assumed that mkmf has setup an exports file for the
- # extension, so we have to create one ourselves.
+ # extension, so we have to to create one ourselves.
when "DEFFILE"
write_deffile(dest_dir, crate_name)
else
@@ -314,6 +313,22 @@ EOF
deffile_path
end
+ # 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
+ def so_ext
+ return RbConfig::CONFIG["SOEXT"] if RbConfig::CONFIG.key?("SOEXT")
+
+ if win_target?
+ "dll"
+ elsif darwin_target?
+ "dylib"
+ else
+ "so"
+ end
+ end
+
# Corresponds to $(LIBPATH) in mkmf
def mkmf_libpath
["-L", "native=#{makefile_config("libdir")}"]
diff --git a/lib/rubygems/ext/configure_builder.rb b/lib/rubygems/ext/configure_builder.rb
index 6b8590ba2e..51106c6370 100644
--- a/lib/rubygems/ext/configure_builder.rb
+++ b/lib/rubygems/ext/configure_builder.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb
index f38fe5947e..27ebd8c62b 100644
--- a/lib/rubygems/ext/ext_conf_builder.rb
+++ b/lib/rubygems/ext/ext_conf_builder.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -22,7 +21,8 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
destdir = ENV["DESTDIR"]
begin
- cmd = ruby << File.basename(extension)
+ require "shellwords"
+ cmd = Gem.ruby.shellsplit << "-I" << File.expand_path("../..", __dir__) << File.basename(extension)
cmd.push(*args)
run(cmd, results, class_name, extension_dir) do |s, r|
@@ -43,12 +43,12 @@ 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[. ..]
entries = entries.map {|entry| File.join full_tmp_dest, entry }
- FileUtils.cp_r entries, lib_dir, remove_destination: true
+ FileUtils.cp_r entries, lib_dir, :remove_destination => true
end
FileUtils::Entry_.new(full_tmp_dest).traverse do |ent|
@@ -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..9f2e099d40 100644
--- a/lib/rubygems/ext/rake_builder.rb
+++ b/lib/rubygems/ext/rake_builder.rb
@@ -1,7 +1,4 @@
# frozen_string_literal: true
-
-require_relative "../shellwords"
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -10,17 +7,18 @@ 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
rake = ENV["rake"]
if rake
- rake = Shellwords.split(rake)
+ require "shellwords"
+ rake = rake.shellsplit
else
begin
- rake = ruby << "-rrubygems" << Gem.bin_path("rake", "rake")
+ rake = [Gem.ruby, "-I#{File.expand_path("../..", __dir__)}", "-rrubygems", Gem.bin_path("rake", "rake")]
rescue Gem::Exception
rake = [Gem.default_exec_format % "rake"]
end
diff --git a/lib/rubygems/gem_runner.rb b/lib/rubygems/gem_runner.rb
index 8335a0ad03..31890a60d7 100644
--- a/lib/rubygems/gem_runner.rb
+++ b/lib/rubygems/gem_runner.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -33,11 +32,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 +40,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 a8361b7ff1..3477422b79 100644
--- a/lib/rubygems/gemcutter_utilities.rb
+++ b/lib/rubygems/gemcutter_utilities.rb
@@ -1,17 +1,14 @@
# frozen_string_literal: true
-
require_relative "remote_fetcher"
require_relative "text"
-require_relative "gemcutter_utilities/webauthn_listener"
-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].freeze
- EXCLUSIVELY_API_SCOPES = [:show_dashboard].freeze
+ API_SCOPES = %i[index_rubygems push_rubygem yank_rubygem add_owner remove_owner access_webhooks show_dashboard].freeze
include Gem::Text
@@ -73,7 +70,8 @@ module Gem::GemcutterUtilities
@host ||=
begin
env_rubygems_host = ENV["RUBYGEMS_HOST"]
- env_rubygems_host = nil if env_rubygems_host&.empty?
+ env_rubygems_host = nil if
+ env_rubygems_host && env_rubygems_host.empty?
env_rubygems_host || configured_host
end
@@ -84,8 +82,8 @@ module Gem::GemcutterUtilities
#
# If +allowed_push_host+ metadata is present, then it will only allow that host.
- def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, scope: nil, credentials: {}, &block)
- require_relative "vendored_net_http"
+ def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, scope: nil, &block)
+ require "net/http"
self.host = host if host
unless self.host
@@ -94,8 +92,8 @@ module Gem::GemcutterUtilities
end
if allowed_push_host
- allowed_host_uri = Gem::URI.parse(allowed_push_host)
- host_uri = Gem::URI.parse(self.host)
+ allowed_host_uri = URI.parse(allowed_push_host)
+ host_uri = URI.parse(self.host)
unless (host_uri.scheme == allowed_host_uri.scheme) && (host_uri.host == allowed_host_uri.host)
alert_error "#{self.host.inspect} is not allowed by the gemspec, which only allows #{allowed_push_host.inspect}"
@@ -103,11 +101,11 @@ module Gem::GemcutterUtilities
end
end
- uri = Gem::URI.parse "#{self.host}/#{path}"
+ uri = URI.parse "#{self.host}/#{path}"
response = request_with_otp(method, uri, &block)
if mfa_unauthorized?(response)
- fetch_otp(credentials)
+ ask_otp
response = request_with_otp(method, uri, &block)
end
@@ -120,27 +118,27 @@ module Gem::GemcutterUtilities
end
def mfa_unauthorized?(response)
- response.is_a?(Gem::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 }
say "The existing key doesn't have access of #{scope} on #{pretty_host}. Please sign in to update access."
- identifier = ask "Username/email: "
- password = ask_for_password " Password: "
+ email = ask " Email: "
+ password = ask_for_password "Password: "
response = rubygems_api_request(:put, "api/v1/api_key",
sign_in_host, scope: scope) do |request|
- request.basic_auth identifier, password
+ request.basic_auth email, password
request["OTP"] = otp if otp
- request.body = Gem::URI.encode_www_form({ api_key: api_key }.merge(update_scope_params))
+ 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
@@ -150,34 +148,33 @@ 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"
- identifier = ask "Username/email: "
- password = ask_for_password " Password: "
+ email = ask " Email: "
+ password = ask_for_password "Password: "
say "\n"
key_name = get_key_name(scope)
scope_params = get_scope_params(scope)
- profile = get_user_profile(identifier, password)
+ profile = get_user_profile(email, password)
mfa_params = get_mfa_params(profile)
all_params = scope_params.merge(mfa_params)
warning = profile["warning"]
- credentials = { identifier: identifier, password: password }
say "#{warning}\n" if warning
response = rubygems_api_request(:post, "api/v1/api_key",
- sign_in_host, credentials: credentials, scope: scope) do |request|
- request.basic_auth identifier, password
+ sign_in_host, scope: scope) do |request|
+ request.basic_auth email, password
request["OTP"] = otp if otp
- request.body = Gem::URI.encode_www_form({ name: key_name }.merge(all_params))
+ request.body = URI.encode_www_form({ name: key_name }.merge(all_params))
end
with_response response do |resp|
@@ -209,14 +206,14 @@ module Gem::GemcutterUtilities
def with_response(response, error_prefix = nil)
case response
- when Gem::Net::HTTPSuccess then
+ when Net::HTTPSuccess then
if block_given?
yield response
else
say clean_text(response.body)
end
- when Gem::Net::HTTPPermanentRedirect, Gem::Net::HTTPRedirection then
- message = "The request has redirected permanently to #{response["location"]}. Please check your defined push host URL."
+ when Net::HTTPPermanentRedirect, Net::HTTPRedirection then
+ 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)
@@ -245,7 +242,7 @@ module Gem::GemcutterUtilities
private
def request_with_otp(method, uri, &block)
- request_method = Gem::Net::HTTP.const_get method.to_s.capitalize
+ request_method = Net::HTTP.const_get method.to_s.capitalize
Gem::RemoteFetcher.fetcher.request(uri, request_method) do |req|
req["OTP"] = otp if otp
@@ -253,52 +250,9 @@ module Gem::GemcutterUtilities
end
end
- def fetch_otp(credentials)
- options[:otp] = if webauthn_url = webauthn_verification_url(credentials)
- server = TCPServer.new 0
- port = server.addr[1].to_s
-
- url_with_port = "#{webauthn_url}?port=#{port}"
- say "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option."
-
- threads = [WebauthnListener.listener_thread(host, server), WebauthnPoller.poll_thread(options, host, webauthn_url, credentials)]
- otp_thread = wait_for_otp_thread(*threads)
-
- threads.each(&:join)
-
- if error = otp_thread[:error]
- alert_error error.message
- terminate_interaction(1)
- end
-
- say "You are verified with a security device. You may close the browser window."
- otp_thread[:otp]
- else
- say "You have enabled multi-factor authentication. Please enter OTP code."
- ask "Code: "
- end
- end
-
- def wait_for_otp_thread(*threads)
- loop do
- threads.each do |otp_thread|
- return otp_thread unless otp_thread.alive?
- end
- sleep 0.1
- end
- ensure
- threads.each(&:exit)
- end
-
- def webauthn_verification_url(credentials)
- response = rubygems_api_request(:post, "api/v1/webauthn_verification") do |request|
- if credentials.empty?
- request.add_field "Authorization", api_key
- else
- request.basic_auth credentials[:identifier], credentials[:password]
- end
- end
- response.is_a?(Gem::Net::HTTPSuccess) ? response.body : nil
+ def ask_otp
+ say "You have enabled multi-factor authentication. Please enter OTP code."
+ options[:otp] = ask "Code: "
end
def pretty_host(host)
@@ -310,31 +264,15 @@ module Gem::GemcutterUtilities
end
def get_scope_params(scope)
- scope_params = { index_rubygems: true }
+ scope_params = {}
if scope
scope_params = { scope => true }
else
- say "The default access scope is:"
- scope_params.each do |k, _v|
- say " #{k}: y"
- end
- say "\n"
- customise = ask_yes_no("Do you want to customise scopes?", false)
- if customise
- EXCLUSIVELY_API_SCOPES.each do |excl_scope|
- selected = ask_yes_no("#{excl_scope} (exclusive scope, answering yes will not prompt for other scopes)", false)
- next unless selected
-
- return { excl_scope => true }
- end
-
- scope_params = {}
-
- API_SCOPES.each do |s|
- selected = ask_yes_no(s.to_s, false)
- scope_params[s] = true if selected
- end
+ say "Please select scopes you want to enable for the API key (y/n)"
+ API_SCOPES.each do |scope|
+ selected = ask_yes_no("#{scope}", false)
+ scope_params[scope] = true if selected
end
say "\n"
end
@@ -343,25 +281,25 @@ module Gem::GemcutterUtilities
end
def default_host?
- host == Gem::DEFAULT_HOST
+ self.host == Gem::DEFAULT_HOST
end
- def get_user_profile(identifier, password)
+ def get_user_profile(email, password)
return {} unless default_host?
response = rubygems_api_request(:get, "api/v1/profile/me.yaml") do |request|
- request.basic_auth identifier, password
+ request.basic_auth email, password
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
@@ -383,6 +321,6 @@ module Gem::GemcutterUtilities
end
def api_key_forbidden?(response)
- response.is_a?(Gem::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/gemcutter_utilities/webauthn_listener.rb b/lib/rubygems/gemcutter_utilities/webauthn_listener.rb
deleted file mode 100644
index abf65efe37..0000000000
--- a/lib/rubygems/gemcutter_utilities/webauthn_listener.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "webauthn_listener/response"
-
-##
-# The WebauthnListener class retrieves an OTP after a user successfully WebAuthns with the Gem host.
-# An instance opens a socket using the TCPServer instance given and listens for a request from the Gem host.
-# The request should be a GET request to the root path and contains the OTP code in the form
-# of a query parameter `code`. The listener will return the code which will be used as the OTP for
-# API requests.
-#
-# Types of responses sent by the listener after receiving a request:
-# - 200 OK: OTP code was successfully retrieved
-# - 204 No Content: If the request was an OPTIONS request
-# - 400 Bad Request: If the request did not contain a query parameter `code`
-# - 404 Not Found: The request was not to the root path
-# - 405 Method Not Allowed: OTP code was not retrieved because the request was not a GET/OPTIONS request
-#
-# Example usage:
-#
-# thread = Gem::WebauthnListener.listener_thread("https://rubygems.example", server)
-# thread.join
-# otp = thread[:otp]
-# error = thread[:error]
-#
-
-module Gem::GemcutterUtilities
- class WebauthnListener
- attr_reader :host
-
- def initialize(host)
- @host = host
- end
-
- def self.listener_thread(host, server)
- Thread.new do
- thread = Thread.current
- thread.abort_on_exception = true
- thread.report_on_exception = false
- thread[:otp] = new(host).wait_for_otp_code(server)
- rescue Gem::WebauthnVerificationError => e
- thread[:error] = e
- ensure
- server.close
- end
- end
-
- def wait_for_otp_code(server)
- loop do
- socket = server.accept
- request_line = socket.gets
-
- method, req_uri, _protocol = request_line.split(" ")
- req_uri = Gem::URI.parse(req_uri)
-
- responder = SocketResponder.new(socket)
-
- unless root_path?(req_uri)
- responder.send(NotFoundResponse.for(host))
- raise Gem::WebauthnVerificationError, "Page at #{req_uri.path} not found."
- end
-
- case method.upcase
- when "OPTIONS"
- responder.send(NoContentResponse.for(host))
- next # will be GET
- when "GET"
- if otp = parse_otp_from_uri(req_uri)
- responder.send(OkResponse.for(host))
- return otp
- end
- responder.send(BadRequestResponse.for(host))
- raise Gem::WebauthnVerificationError, "Did not receive OTP from #{host}."
- else
- responder.send(MethodNotAllowedResponse.for(host))
- raise Gem::WebauthnVerificationError, "Invalid HTTP method #{method.upcase} received."
- end
- end
- end
-
- private
-
- def root_path?(uri)
- uri.path == "/"
- end
-
- def parse_otp_from_uri(uri)
- require "cgi"
-
- return if uri.query.nil?
- CGI.parse(uri.query).dig("code", 0)
- end
-
- class SocketResponder
- def initialize(socket)
- @socket = socket
- end
-
- def send(response)
- @socket.print response.to_s
- @socket.close
- end
- end
- end
-end
diff --git a/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb b/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb
deleted file mode 100644
index 17baa64fff..0000000000
--- a/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb
+++ /dev/null
@@ -1,163 +0,0 @@
-# frozen_string_literal: true
-
-##
-# The WebauthnListener Response class is used by the WebauthnListener to create
-# responses to be sent to the Gem host. It creates a Gem::Net::HTTPResponse instance
-# when initialized and can be converted to the appropriate format to be sent by a socket using `to_s`.
-# Gem::Net::HTTPResponse instances cannot be directly sent over a socket.
-#
-# Types of response classes:
-# - OkResponse
-# - NoContentResponse
-# - BadRequestResponse
-# - NotFoundResponse
-# - MethodNotAllowedResponse
-#
-# Example usage:
-#
-# server = TCPServer.new(0)
-# socket = server.accept
-#
-# response = OkResponse.for("https://rubygems.example")
-# socket.print response.to_s
-# socket.close
-#
-
-module Gem::GemcutterUtilities
- class WebauthnListener
- class Response
- attr_reader :http_response
-
- def self.for(host)
- new(host)
- end
-
- def initialize(host)
- @host = host
-
- build_http_response
- end
-
- def to_s
- status_line = "HTTP/#{@http_response.http_version} #{@http_response.code} #{@http_response.message}\r\n"
- headers = @http_response.to_hash.map {|header, value| "#{header}: #{value.join(", ")}\r\n" }.join + "\r\n"
- body = @http_response.body ? "#{@http_response.body}\n" : ""
-
- status_line + headers + body
- end
-
- private
-
- # Must be implemented in subclasses
- def code
- raise NotImplementedError
- end
-
- def reason_phrase
- raise NotImplementedError
- end
-
- def body; end
-
- def build_http_response
- response_class = Gem::Net::HTTPResponse::CODE_TO_OBJ[code.to_s]
- @http_response = response_class.new("1.1", code, reason_phrase)
- @http_response.instance_variable_set(:@read, true)
-
- add_connection_header
- add_access_control_headers
- add_body
- end
-
- def add_connection_header
- @http_response["connection"] = "close"
- end
-
- def add_access_control_headers
- @http_response["access-control-allow-origin"] = @host
- @http_response["access-control-allow-methods"] = "POST"
- @http_response["access-control-allow-headers"] = %w[Content-Type Authorization x-csrf-token]
- end
-
- def add_body
- return unless body
- @http_response["content-type"] = "text/plain; charset=utf-8"
- @http_response["content-length"] = body.bytesize
- @http_response.instance_variable_set(:@body, body)
- end
- end
-
- class OkResponse < Response
- private
-
- def code
- 200
- end
-
- def reason_phrase
- "OK"
- end
-
- def body
- "success"
- end
- end
-
- class NoContentResponse < Response
- private
-
- def code
- 204
- end
-
- def reason_phrase
- "No Content"
- end
- end
-
- class BadRequestResponse < Response
- private
-
- def code
- 400
- end
-
- def reason_phrase
- "Bad Request"
- end
-
- def body
- "missing code parameter"
- end
- end
-
- class NotFoundResponse < Response
- private
-
- def code
- 404
- end
-
- def reason_phrase
- "Not Found"
- end
- end
-
- class MethodNotAllowedResponse < Response
- private
-
- def code
- 405
- end
-
- def reason_phrase
- "Method Not Allowed"
- end
-
- def add_access_control_headers
- super
- @http_response["allow"] = %w[GET OPTIONS]
- end
- end
- end
-end
diff --git a/lib/rubygems/gemcutter_utilities/webauthn_poller.rb b/lib/rubygems/gemcutter_utilities/webauthn_poller.rb
deleted file mode 100644
index fe3f163a88..0000000000
--- a/lib/rubygems/gemcutter_utilities/webauthn_poller.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-
-##
-# The WebauthnPoller class retrieves an OTP after a user successfully WebAuthns. An instance
-# polls the Gem host for the OTP code. The polling request (api/v1/webauthn_verification/<webauthn_token>/status.json)
-# is sent to the Gem host every 5 seconds and will timeout after 5 minutes. If the status field in the json response
-# is "success", the code field will contain the OTP code.
-#
-# Example usage:
-#
-# thread = Gem::WebauthnPoller.poll_thread(
-# {},
-# "RubyGems.org",
-# "https://rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY",
-# { email: "email@example.com", password: "password" }
-# )
-# thread.join
-# otp = thread[:otp]
-# error = thread[:error]
-#
-
-module Gem::GemcutterUtilities
- class WebauthnPoller
- include Gem::GemcutterUtilities
- TIMEOUT_IN_SECONDS = 300
-
- attr_reader :options, :host
-
- def initialize(options, host)
- @options = options
- @host = host
- end
-
- def self.poll_thread(options, host, webauthn_url, credentials)
- Thread.new do
- thread = Thread.current
- thread.abort_on_exception = true
- thread.report_on_exception = false
- thread[:otp] = new(options, host).poll_for_otp(webauthn_url, credentials)
- rescue Gem::WebauthnVerificationError, Gem::Timeout::Error => e
- thread[:error] = e
- end
- end
-
- def poll_for_otp(webauthn_url, credentials)
- Gem::Timeout.timeout(TIMEOUT_IN_SECONDS) do
- loop do
- response = webauthn_verification_poll_response(webauthn_url, credentials)
- raise Gem::WebauthnVerificationError, response.message unless response.is_a?(Gem::Net::HTTPSuccess)
-
- require "json"
- parsed_response = JSON.parse(response.body)
- case parsed_response["status"]
- when "pending"
- sleep 5
- when "success"
- return parsed_response["code"]
- else
- raise Gem::WebauthnVerificationError, parsed_response.fetch("message", "Invalid response from server")
- end
- end
- end
- end
-
- private
-
- def webauthn_verification_poll_response(webauthn_url, credentials)
- webauthn_token = %r{(?<=\/)[^\/]+(?=$)}.match(webauthn_url)[0]
- rubygems_api_request(:get, "api/v1/webauthn_verification/#{webauthn_token}/status.json") do |request|
- if credentials.empty?
- request.add_field "Authorization", api_key
- elsif credentials[:identifier] && credentials[:password]
- request.basic_auth credentials[:identifier], credentials[:password]
- else
- raise Gem::WebauthnVerificationError, "Provided missing credentials"
- end
- end
- end
- end
-end
diff --git a/lib/rubygems/gemspec_helpers.rb b/lib/rubygems/gemspec_helpers.rb
deleted file mode 100644
index 2b20fcafa1..0000000000
--- a/lib/rubygems/gemspec_helpers.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../rubygems"
-
-##
-# Mixin methods for commands that work with gemspecs.
-
-module Gem::GemspecHelpers
- def find_gemspec(glob = "*.gemspec")
- gemspecs = Dir.glob(glob).sort
-
- if gemspecs.size > 1
- alert_error "Multiple gemspecs found: #{gemspecs}, please specify one"
- terminate_interaction(1)
- end
-
- gemspecs.first
- end
-end
diff --git a/lib/rubygems/indexer.rb b/lib/rubygems/indexer.rb
new file mode 100644
index 0000000000..d0061ff82e
--- /dev/null
+++ b/lib/rubygems/indexer.rb
@@ -0,0 +1,427 @@
+# frozen_string_literal: true
+require_relative "../rubygems"
+require_relative "package"
+require "tmpdir"
+
+##
+# Top level class for building the gem repository index.
+
+class Gem::Indexer
+ include Gem::UserInteraction
+
+ ##
+ # Build indexes for RubyGems 1.2.0 and newer when true
+
+ attr_accessor :build_modern
+
+ ##
+ # Index install location
+
+ attr_reader :dest_directory
+
+ ##
+ # Specs index install location
+
+ attr_reader :dest_specs_index
+
+ ##
+ # Latest specs index install location
+
+ attr_reader :dest_latest_specs_index
+
+ ##
+ # Prerelease specs index install location
+
+ attr_reader :dest_prerelease_specs_index
+
+ ##
+ # Index build directory
+
+ attr_reader :directory
+
+ ##
+ # Create an indexer that will index the gems in +directory+.
+
+ def initialize(directory, options = {})
+ require "fileutils"
+ require "tmpdir"
+ require "zlib"
+
+ options = { :build_modern => true }.merge options
+
+ @build_modern = options[:build_modern]
+
+ @dest_directory = directory
+ @directory = Dir.mktmpdir "gem_generate_index"
+
+ marshal_name = "Marshal.#{Gem.marshal_version}"
+
+ @master_index = File.join @directory, "yaml"
+ @marshal_index = File.join @directory, marshal_name
+
+ @quick_dir = File.join @directory, "quick"
+ @quick_marshal_dir = File.join @quick_dir, marshal_name
+ @quick_marshal_dir_base = File.join "quick", marshal_name # FIX: UGH
+
+ @quick_index = File.join @quick_dir, "index"
+ @latest_index = File.join @quick_dir, "latest_index"
+
+ @specs_index = File.join @directory, "specs.#{Gem.marshal_version}"
+ @latest_specs_index =
+ File.join(@directory, "latest_specs.#{Gem.marshal_version}")
+ @prerelease_specs_index =
+ File.join(@directory, "prerelease_specs.#{Gem.marshal_version}")
+ @dest_specs_index =
+ File.join(@dest_directory, "specs.#{Gem.marshal_version}")
+ @dest_latest_specs_index =
+ File.join(@dest_directory, "latest_specs.#{Gem.marshal_version}")
+ @dest_prerelease_specs_index =
+ File.join(@dest_directory, "prerelease_specs.#{Gem.marshal_version}")
+
+ @files = []
+ end
+
+ ##
+ # Build various indices
+
+ def build_indices
+ specs = map_gems_to_specs gem_file_list
+ Gem::Specification._resort! specs
+ build_marshal_gemspecs specs
+ build_modern_indices specs if @build_modern
+
+ compress_indices
+ end
+
+ ##
+ # Builds Marshal quick index gemspecs.
+
+ def build_marshal_gemspecs(specs)
+ count = specs.count
+ progress = ui.progress_reporter count,
+ "Generating Marshal quick index gemspecs for #{count} gems",
+ "Complete"
+
+ files = []
+
+ Gem.time "Generated Marshal quick index gemspecs" do
+ specs.each do |spec|
+ next if spec.default_gem?
+ spec_file_name = "#{spec.original_name}.gemspec.rz"
+ marshal_name = File.join @quick_marshal_dir, spec_file_name
+
+ marshal_zipped = Gem.deflate Marshal.dump(spec)
+
+ File.open marshal_name, "wb" do |io|
+ io.write marshal_zipped
+ end
+
+ files << marshal_name
+
+ progress.updated spec.original_name
+ end
+
+ progress.done
+ end
+
+ @files << @quick_marshal_dir
+
+ files
+ end
+
+ ##
+ # Build a single index for RubyGems 1.2 and newer
+
+ def build_modern_index(index, file, name)
+ say "Generating #{name} index"
+
+ Gem.time "Generated #{name} index" do
+ File.open(file, "wb") do |io|
+ specs = index.map do |*spec|
+ # We have to splat here because latest_specs is an array, while the
+ # others are hashes.
+ spec = spec.flatten.last
+ platform = spec.original_platform
+
+ # win32-api-1.0.4-x86-mswin32-60
+ unless String === platform
+ alert_warning "Skipping invalid platform in gem: #{spec.full_name}"
+ next
+ end
+
+ platform = Gem::Platform::RUBY if platform.nil? || platform.empty?
+ [spec.name, spec.version, platform]
+ end
+
+ specs = compact_specs(specs)
+ Marshal.dump(specs, io)
+ end
+ end
+ end
+
+ ##
+ # Builds indices for RubyGems 1.2 and newer. Handles full, latest, prerelease
+
+ def build_modern_indices(specs)
+ prerelease, released = specs.partition do |s|
+ s.version.prerelease?
+ end
+ latest_specs =
+ Gem::Specification._latest_specs specs
+
+ build_modern_index(released.sort, @specs_index, "specs")
+ build_modern_index(latest_specs.sort, @latest_specs_index, "latest specs")
+ build_modern_index(prerelease.sort, @prerelease_specs_index,
+ "prerelease specs")
+
+ @files += [@specs_index,
+ "#{@specs_index}.gz",
+ @latest_specs_index,
+ "#{@latest_specs_index}.gz",
+ @prerelease_specs_index,
+ "#{@prerelease_specs_index}.gz"]
+ end
+
+ def map_gems_to_specs(gems)
+ gems.map do |gemfile|
+ if File.size(gemfile) == 0
+ alert_warning "Skipping zero-length gem: #{gemfile}"
+ next
+ end
+
+ begin
+ spec = Gem::Package.new(gemfile).spec
+ spec.loaded_from = gemfile
+
+ spec.abbreviate
+ spec.sanitize
+
+ spec
+ rescue SignalException
+ alert_error "Received signal, exiting"
+ raise
+ rescue Exception => e
+ msg = ["Unable to process #{gemfile}",
+ "#{e.message} (#{e.class})",
+ "\t#{e.backtrace.join "\n\t"}"].join("\n")
+ alert_error msg
+ end
+ end.compact
+ end
+
+ ##
+ # Compresses indices on disk
+ #--
+ # All future files should be compressed using gzip, not deflate
+
+ def compress_indices
+ say "Compressing indices"
+
+ Gem.time "Compressed indices" do
+ if @build_modern
+ gzip @specs_index
+ gzip @latest_specs_index
+ gzip @prerelease_specs_index
+ end
+ end
+ end
+
+ ##
+ # Compacts Marshal output for the specs index data source by using identical
+ # objects as much as possible.
+
+ def compact_specs(specs)
+ names = {}
+ versions = {}
+ platforms = {}
+
+ specs.map do |(name, version, platform)|
+ names[name] = name unless names.include? name
+ versions[version] = version unless versions.include? version
+ platforms[platform] = platform unless platforms.include? platform
+
+ [names[name], versions[version], platforms[platform]]
+ end
+ end
+
+ ##
+ # Compress +filename+ with +extension+.
+
+ def compress(filename, extension)
+ data = Gem.read_binary filename
+
+ zipped = Gem.deflate data
+
+ File.open "#{filename}.#{extension}", "wb" do |io|
+ io.write zipped
+ end
+ end
+
+ ##
+ # List of gem file names to index.
+
+ def gem_file_list
+ Gem::Util.glob_files_in_dir("*.gem", File.join(@dest_directory, "gems"))
+ end
+
+ ##
+ # Builds and installs indices.
+
+ def generate_index
+ make_temp_directories
+ build_indices
+ install_indices
+ rescue SignalException
+ ensure
+ FileUtils.rm_rf @directory
+ end
+
+ ##
+ # Zlib::GzipWriter wrapper that gzips +filename+ on disk.
+
+ def gzip(filename)
+ Zlib::GzipWriter.open "#{filename}.gz" do |io|
+ io.write Gem.read_binary(filename)
+ end
+ end
+
+ ##
+ # Install generated indices into the destination directory.
+
+ def install_indices
+ verbose = Gem.configuration.really_verbose
+
+ say "Moving index into production dir #{@dest_directory}" if verbose
+
+ files = @files
+ files.delete @quick_marshal_dir if files.include? @quick_dir
+
+ if files.include?(@quick_marshal_dir) && !files.include?(@quick_dir)
+ files.delete @quick_marshal_dir
+
+ dst_name = File.join(@dest_directory, @quick_marshal_dir_base)
+
+ FileUtils.mkdir_p File.dirname(dst_name), :verbose => verbose
+ FileUtils.rm_rf dst_name, :verbose => verbose
+ FileUtils.mv(@quick_marshal_dir, dst_name,
+ :verbose => verbose, :force => true)
+ end
+
+ files = files.map do |path|
+ path.sub(/^#{Regexp.escape @directory}\/?/, "") # HACK?
+ end
+
+ files.each do |file|
+ src_name = File.join @directory, file
+ dst_name = File.join @dest_directory, file
+
+ FileUtils.rm_rf dst_name, :verbose => verbose
+ FileUtils.mv(src_name, @dest_directory,
+ :verbose => verbose, :force => true)
+ end
+ end
+
+ ##
+ # Make directories for index generation
+
+ def make_temp_directories
+ FileUtils.rm_rf @directory
+ FileUtils.mkdir_p @directory, :mode => 0700
+ FileUtils.mkdir_p @quick_marshal_dir
+ end
+
+ ##
+ # Ensure +path+ and path with +extension+ are identical.
+
+ def paranoid(path, extension)
+ data = Gem.read_binary path
+ compressed_data = Gem.read_binary "#{path}.#{extension}"
+
+ unless data == Gem::Util.inflate(compressed_data)
+ raise "Compressed file #{compressed_path} does not match uncompressed file #{path}"
+ end
+ end
+
+ ##
+ # Perform an in-place update of the repository from newly added gems.
+
+ def update_index
+ make_temp_directories
+
+ specs_mtime = File.stat(@dest_specs_index).mtime
+ newest_mtime = Time.at 0
+
+ updated_gems = gem_file_list.select do |gem|
+ gem_mtime = File.stat(gem).mtime
+ newest_mtime = gem_mtime if gem_mtime > newest_mtime
+ gem_mtime >= specs_mtime
+ end
+
+ if updated_gems.empty?
+ say "No new gems"
+ terminate_interaction 0
+ end
+
+ specs = map_gems_to_specs updated_gems
+ prerelease, released = specs.partition {|s| s.version.prerelease? }
+
+ files = build_marshal_gemspecs specs
+
+ Gem.time "Updated indexes" do
+ update_specs_index released, @dest_specs_index, @specs_index
+ update_specs_index released, @dest_latest_specs_index, @latest_specs_index
+ update_specs_index(prerelease,
+ @dest_prerelease_specs_index,
+ @prerelease_specs_index)
+ end
+
+ compress_indices
+
+ verbose = Gem.configuration.really_verbose
+
+ say "Updating production dir #{@dest_directory}" if verbose
+
+ files << @specs_index
+ files << "#{@specs_index}.gz"
+ files << @latest_specs_index
+ files << "#{@latest_specs_index}.gz"
+ files << @prerelease_specs_index
+ files << "#{@prerelease_specs_index}.gz"
+
+ files = files.map do |path|
+ path.sub(/^#{Regexp.escape @directory}\/?/, "") # HACK?
+ end
+
+ files.each do |file|
+ src_name = File.join @directory, file
+ dst_name = File.join @dest_directory, file # REFACTOR: duped above
+
+ FileUtils.mv src_name, dst_name, :verbose => verbose,
+ :force => true
+
+ File.utime newest_mtime, newest_mtime, dst_name
+ end
+ ensure
+ FileUtils.rm_rf @directory
+ end
+
+ ##
+ # Combines specs in +index+ and +source+ then writes out a new copy to
+ # +dest+. For a latest index, does not ensure the new file is minimal.
+
+ def update_specs_index(index, source, dest)
+ specs_index = Marshal.load Gem.read_binary(source)
+
+ index.each do |spec|
+ platform = spec.original_platform
+ platform = Gem::Platform::RUBY if platform.nil? || platform.empty?
+ specs_index << [spec.name, spec.version, platform]
+ end
+
+ specs_index = compact_specs specs_index.uniq.sort
+
+ File.open dest, "wb" do |io|
+ Marshal.dump specs_index, io
+ end
+ end
+end
diff --git a/lib/rubygems/install_default_message.rb b/lib/rubygems/install_default_message.rb
index 0640eaaf08..0d112a15df 100644
--- a/lib/rubygems/install_default_message.rb
+++ b/lib/rubygems/install_default_message.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../rubygems"
require_relative "user_interaction"
diff --git a/lib/rubygems/install_message.rb b/lib/rubygems/install_message.rb
index a24e26b918..2565f36261 100644
--- a/lib/rubygems/install_message.rb
+++ b/lib/rubygems/install_message.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../rubygems"
require_relative "user_interaction"
diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb
index aad207a718..79effcf21f 100644
--- a/lib/rubygems/install_update_options.rb
+++ b/lib/rubygems/install_update_options.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -36,9 +35,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 +49,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 +59,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 +103,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 +135,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 +153,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
@@ -186,7 +185,7 @@ module Gem::InstallUpdateOptions
def install_update_options
{
- document: %w[ri],
+ :document => %w[ri],
}
end
@@ -196,4 +195,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 b374824b2a..9fbb2824c7 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -66,6 +65,8 @@ class Gem::Installer
attr_reader :package
+ @path_warning = false
+
class << self
#
# Changes in rubygems to lazily loading `rubygems/command` (in order to
@@ -85,6 +86,11 @@ class Gem::Installer
end
##
+ # True if we've warned about PATH not including Gem.bindir
+
+ attr_accessor :path_warning
+
+ ##
# Overrides the executable format.
#
# This is a sprintf format with a "%s" which will be replaced with the
@@ -181,6 +187,13 @@ class Gem::Installer
@package.dir_mode = options[:dir_mode]
@package.prog_mode = options[:prog_mode]
@package.data_mode = options[:data_mode]
+
+ 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
##
@@ -208,32 +221,31 @@ class Gem::Installer
File.open generated_bin, "rb" do |io|
line = io.gets
- shebang = /^#!.*ruby/o
+ shebang = /^#!.*ruby/
- # TruffleRuby uses a bash prelude in default launchers
- if load_relative_enabled? || RUBY_ENGINE == "truffleruby"
- until line.nil? || shebang.match?(line) do
+ if load_relative_enabled?
+ until line.nil? || line =~ shebang do
line = io.gets
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&.include?("This file was generated by RubyGems")
+ 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
@@ -303,7 +315,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
@@ -328,37 +340,39 @@ class Gem::Installer
say spec.post_install_message if options[:post_install_message] && !spec.post_install_message.nil?
- Gem::Specification.add_spec(spec) unless @install_dir
-
- load_plugin
+ Gem::Specification.add_spec(spec)
run_post_install_hooks
spec
- rescue Errno::EACCES => e
- # Permission denied - /path/to/foo
- raise Gem::FilePermissionError, e.message.split(" - ").last
+
+ # 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
@@ -374,11 +388,11 @@ class Gem::Installer
# we'll be installing into.
def installed_specs
- @installed_specs ||= begin
+ @specs ||= begin
specs = []
Gem::Util.glob_files_in_dir("*.gemspec", File.join(gem_home, "specifications")).each do |path|
- spec = Gem::Specification.load path
+ spec = Gem::Specification.load path.tap(&Gem::UNTAINT)
specs << spec if spec
end
@@ -448,9 +462,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)
@@ -472,29 +483,21 @@ class Gem::Installer
end
def generate_bin # :nodoc:
- executables = spec.executables
- return if executables.nil? || executables.empty?
-
- 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`
-
- check_that_user_bin_dir_is_in_path(executables)
- end
+ return if spec.executables.nil? || spec.executables.empty?
ensure_writable_dir @bin_dir
- executables.each do |filename|
+ spec.executables.each do |filename|
+ filename.tap(&Gem::UNTAINT)
bin_path = File.join gem_dir, spec.bindir, filename
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
- File.chmod dir_mode, bin_path
+ require "fileutils"
+ FileUtils.chmod dir_mode, bin_path
end
check_executable_overwrite filename
@@ -518,8 +521,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
##
@@ -527,19 +528,17 @@ 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)
- Gem.open_file_with_lock(bin_script_path) do
- require "fileutils"
- FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
+ 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.write app_script_text(filename)
- file.chmod(options[:prog_mode] || 0o755)
- end
+ File.open bin_script_path, "wb", 0755 do |file|
+ file.print app_script_text(filename)
+ file.chmod(options[:prog_mode] || 0755)
end
verbose bin_script_path
@@ -564,7 +563,7 @@ class Gem::Installer
File.unlink dst
end
- FileUtils.symlink src, dst, verbose: Gem.configuration.really_verbose
+ FileUtils.symlink src, dst, :verbose => Gem.configuration.really_verbose
rescue NotImplementedError, SystemCallError
alert_warning "Unable to use symlinks, installing wrapper"
generate_bin_script filename, bindir
@@ -587,7 +586,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.
@@ -629,6 +628,7 @@ class Gem::Installer
def ensure_loadable_spec
ruby = spec.to_ruby_for_cache
+ ruby.tap(&Gem::UNTAINT)
begin
eval ruby
@@ -649,36 +649,31 @@ class Gem::Installer
def process_options # :nodoc:
@options = {
- bin_dir: nil,
- env_shebang: false,
- force: false,
- only_install_dir: false,
- post_install_message: true,
+ :bin_dir => nil,
+ :env_shebang => false,
+ :force => false,
+ :only_install_dir => false,
+ :post_install_message => true,
}.merge options
@env_shebang = options[:env_shebang]
@force = options[:force]
@install_dir = options[:install_dir]
- @user_install = options[:user_install]
+ @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 || user_install_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]:/, ""))
@@ -688,7 +683,9 @@ class Gem::Installer
end
end
- def check_that_user_bin_dir_is_in_path(executables) # :nodoc:
+ def check_that_user_bin_dir_is_in_path # :nodoc:
+ return if self.class.path_warning
+
user_bin_dir = @bin_dir || Gem.bindir(gem_home)
user_bin_dir = user_bin_dir.tr(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
@@ -704,17 +701,19 @@ class Gem::Installer
unless path.include? user_bin_dir
unless !Gem.win_platform? && (path.include? user_bin_dir.sub(ENV["HOME"], "~"))
- alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t gem executables (#{executables.join(", ")}) will not run."
+ alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t gem executables will not run."
+ self.class.path_warning = true
end
end
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
@@ -726,11 +725,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
@@ -747,9 +746,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.
@@ -806,10 +805,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
@@ -931,7 +930,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"
@@ -954,7 +953,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
@@ -964,19 +963,6 @@ TEXT
private
- def user_install_dir
- # never install to user home in --build-root mode
- return unless @build_root.nil?
-
- # Please note that @user_install might have three states:
- # * `true`: `--user-install`
- # * `false`: `--no-user-install` and
- # * `nil`: option was not specified
- if @user_install || (@user_install.nil? && Gem.default_user_install)
- Gem.user_dir
- end
- end
-
def build_args
@build_args ||= begin
require_relative "command"
@@ -1002,7 +988,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
@@ -1016,17 +1002,4 @@ TEXT
""
end
end
-
- def load_plugin
- specs = Gem::Specification.find_all_by_name(spec.name)
- # If old version already exists, this plugin isn't loaded
- # immediately. It's for avoiding a case that multiple versions
- # are loaded at the same time.
- return unless specs.size == 1
-
- plugin_files = spec.plugins.map do |plugin|
- File.join(@plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}")
- end
- Gem.load_plugin_files(plugin_files)
- end
end
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 51a61213a5..b2c2dea905 100644
--- a/lib/rubygems/local_remote_options.rb
+++ b/lib/rubygems/local_remote_options.rb
@@ -1,26 +1,26 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
# See LICENSE.txt for permissions.
#++
-require_relative "vendor/uri/lib/uri"
+require "uri"
require_relative "../rubygems"
##
# Mixin methods for local and remote Gem::Command options.
module Gem::LocalRemoteOptions
+
##
# Allows Gem::OptionParser to handle HTTP URIs.
def accept_uri_http
- Gem::OptionParser.accept Gem::URI::HTTP do |value|
+ Gem::OptionParser.accept URI::HTTP do |value|
begin
- uri = Gem::URI.parse value
- rescue Gem::URI::InvalidURIError
+ uri = URI.parse value
+ rescue URI::InvalidURIError
raise Gem::OptionParser::InvalidArgument, value
end
@@ -39,17 +39,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 +66,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 +77,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
@@ -88,9 +89,9 @@ module Gem::LocalRemoteOptions
def add_proxy_option
accept_uri_http
- add_option(:"Local/Remote", "-p", "--[no-]http-proxy [URL]", Gem::URI::HTTP,
+ 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
@@ -101,9 +102,9 @@ module Gem::LocalRemoteOptions
def add_source_option
accept_uri_http
- add_option(:"Local/Remote", "-s", "--source URL", Gem::URI::HTTP,
+ 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 +119,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 +144,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..5cc67ad099
--- /dev/null
+++ b/lib/rubygems/mock_gem_ui.rb
@@ -0,0 +1,85 @@
+# 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 3f4a6fcf3d..767dc1fb45 100644
--- a/lib/rubygems/name_tuple.rb
+++ b/lib/rubygems/name_tuple.rb
@@ -1,17 +1,18 @@
# frozen_string_literal: true
-
##
#
# Represents a gem of name +name+ at +version+ of +platform+. These
# 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 +31,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,11 +48,11 @@ class Gem::NameTuple
def full_name
case @platform
- when nil, "", Gem::Platform::RUBY
+ when nil, "ruby", ""
"#{@name}-#{@version}"
else
"#{@name}-#{@version}-#{@platform}"
- end
+ end.dup.tap(&Gem::UNTAINT)
end
##
@@ -85,7 +86,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/optparse.rb b/lib/rubygems/optparse.rb
new file mode 100644
index 0000000000..6ed718423c
--- /dev/null
+++ b/lib/rubygems/optparse.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require_relative "optparse/lib/optparse"
diff --git a/lib/bundler/vendor/connection_pool/.document b/lib/rubygems/optparse/.document
index 0c43bbd6b3..0c43bbd6b3 100644
--- a/lib/bundler/vendor/connection_pool/.document
+++ b/lib/rubygems/optparse/.document
diff --git a/lib/rubygems/vendor/optparse/lib/optionparser.rb b/lib/rubygems/optparse/lib/optionparser.rb
index 4b9b40d82a..4b9b40d82a 100644
--- a/lib/rubygems/vendor/optparse/lib/optionparser.rb
+++ b/lib/rubygems/optparse/lib/optionparser.rb
diff --git a/lib/rubygems/optparse/lib/optparse.rb b/lib/rubygems/optparse/lib/optparse.rb
new file mode 100644
index 0000000000..1e50bda769
--- /dev/null
+++ b/lib/rubygems/optparse/lib/optparse.rb
@@ -0,0 +1,2308 @@
+# frozen_string_literal: true
+#
+# optparse.rb - command-line option analysis with the Gem::OptionParser class.
+#
+# Author:: Nobu Nakada
+# Documentation:: Nobu Nakada and Gavin Sinclair.
+#
+# See Gem::OptionParser for documentation.
+#
+
+
+#--
+# == Developer Documentation (not for RDoc output)
+#
+# === Class tree
+#
+# - Gem::OptionParser:: front end
+# - Gem::OptionParser::Switch:: each switches
+# - Gem::OptionParser::List:: options list
+# - Gem::OptionParser::ParseError:: errors on parsing
+# - Gem::OptionParser::AmbiguousOption
+# - Gem::OptionParser::NeedlessArgument
+# - Gem::OptionParser::MissingArgument
+# - Gem::OptionParser::InvalidOption
+# - Gem::OptionParser::InvalidArgument
+# - Gem::OptionParser::AmbiguousArgument
+#
+# === Object relationship diagram
+#
+# +--------------+
+# | Gem::OptionParser |<>-----+
+# +--------------+ | +--------+
+# | ,-| Switch |
+# on_head -------->+---------------+ / +--------+
+# accept/reject -->| List |<|>-
+# | |<|>- +----------+
+# on ------------->+---------------+ `-| argument |
+# : : | class |
+# +---------------+ |==========|
+# on_tail -------->| | |pattern |
+# +---------------+ |----------|
+# Gem::OptionParser.accept ->| DefaultList | |converter |
+# reject |(shared between| +----------+
+# | all instances)|
+# +---------------+
+#
+#++
+#
+# == Gem::OptionParser
+#
+# === New to \Gem::OptionParser?
+#
+# See the {Tutorial}[optparse/tutorial.rdoc].
+#
+# === Introduction
+#
+# Gem::OptionParser is a class for command-line option analysis. It is much more
+# advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented
+# solution.
+#
+# === Features
+#
+# 1. The argument specification and the code to handle it are written in the
+# same place.
+# 2. It can output an option summary; you don't need to maintain this string
+# separately.
+# 3. Optional and mandatory arguments are specified very gracefully.
+# 4. Arguments can be automatically converted to a specified class.
+# 5. Arguments can be restricted to a certain set.
+#
+# All of these features are demonstrated in the examples below. See
+# #make_switch for full documentation.
+#
+# === Minimal example
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# options = {}
+# Gem::OptionParser.new do |parser|
+# parser.banner = "Usage: example.rb [options]"
+#
+# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
+# options[:verbose] = v
+# end
+# end.parse!
+#
+# p options
+# p ARGV
+#
+# === Generating Help
+#
+# Gem::OptionParser can be used to automatically generate help for the commands you
+# write:
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# Options = Struct.new(:name)
+#
+# class Parser
+# def self.parse(options)
+# args = Options.new("world")
+#
+# opt_parser = Gem::OptionParser.new do |parser|
+# parser.banner = "Usage: example.rb [options]"
+#
+# parser.on("-nNAME", "--name=NAME", "Name to say hello to") do |n|
+# args.name = n
+# end
+#
+# parser.on("-h", "--help", "Prints this help") do
+# puts parser
+# exit
+# end
+# end
+#
+# opt_parser.parse!(options)
+# return args
+# end
+# end
+# options = Parser.parse %w[--help]
+#
+# #=>
+# # Usage: example.rb [options]
+# # -n, --name=NAME Name to say hello to
+# # -h, --help Prints this help
+#
+# === Required Arguments
+#
+# For options that require an argument, option specification strings may include an
+# option name in all caps. If an option is used without the required argument,
+# an exception will be raised.
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# options = {}
+# Gem::OptionParser.new do |parser|
+# parser.on("-r", "--require LIBRARY",
+# "Require the LIBRARY before executing your script") do |lib|
+# puts "You required #{lib}!"
+# end
+# end.parse!
+#
+# Used:
+#
+# $ ruby optparse-test.rb -r
+# optparse-test.rb:9:in `<main>': missing argument: -r (Gem::OptionParser::MissingArgument)
+# $ ruby optparse-test.rb -r my-library
+# You required my-library!
+#
+# === Type Coercion
+#
+# Gem::OptionParser supports the ability to coerce command line arguments
+# into objects for us.
+#
+# Gem::OptionParser comes with a few ready-to-use kinds of type
+# coercion. They are:
+#
+# - 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)
+# - Numeric -- Any integer, float, or rational (1, 3.4, 1/3)
+# - DecimalInteger -- Like +Integer+, but no octal format.
+# - OctalInteger -- Like +Integer+, but no decimal format.
+# - DecimalNumeric -- Decimal integer or float.
+# - TrueClass -- Accepts '+, yes, true, -, no, false' and
+# defaults as +true+
+# - FalseClass -- Same as +TrueClass+, but defaults to +false+
+# - Array -- Strings separated by ',' (e.g. 1,2,3)
+# - Regexp -- Regular expressions. Also includes options.
+#
+# We can also add our own coercions, which we will cover below.
+#
+# ==== Using Built-in Conversions
+#
+# As an example, the built-in +Time+ conversion is used. The other built-in
+# conversions behave in the same way.
+# Gem::OptionParser will attempt to parse the argument
+# as a +Time+. If it succeeds, that time will be passed to the
+# handler block. Otherwise, an exception will be raised.
+#
+# require 'rubygems/optparse/lib/optparse'
+# require 'rubygems/optparse/lib/optparse/time'
+# Gem::OptionParser.new do |parser|
+# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
+# p time
+# end
+# end.parse!
+#
+# Used:
+#
+# $ ruby optparse-test.rb -t nonsense
+# ... invalid argument: -t nonsense (Gem::OptionParser::InvalidArgument)
+# $ ruby optparse-test.rb -t 10-11-12
+# 2010-11-12 00:00:00 -0500
+# $ ruby optparse-test.rb -t 9:30
+# 2014-08-13 09:30:00 -0400
+#
+# ==== Creating Custom Conversions
+#
+# The +accept+ method on Gem::OptionParser may be used to create converters.
+# It specifies which conversion block to call whenever a class is specified.
+# The example below uses it to fetch a +User+ object before the +on+ handler receives it.
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# User = Struct.new(:id, :name)
+#
+# def find_user id
+# not_found = ->{ raise "No User Found for id #{id}" }
+# [ User.new(1, "Sam"),
+# User.new(2, "Gandalf") ].find(not_found) do |u|
+# u.id == id
+# end
+# end
+#
+# op = Gem::OptionParser.new
+# op.accept(User) do |user_id|
+# find_user user_id.to_i
+# end
+#
+# op.on("--user ID", User) do |user|
+# puts user
+# end
+#
+# op.parse!
+#
+# Used:
+#
+# $ ruby optparse-test.rb --user 1
+# #<struct User id=1, name="Sam">
+# $ ruby optparse-test.rb --user 2
+# #<struct User id=2, name="Gandalf">
+# $ ruby optparse-test.rb --user 3
+# optparse-test.rb:15:in `block in find_user': No User Found for id 3 (RuntimeError)
+#
+# === Store options to a Hash
+#
+# The +into+ option of +order+, +parse+ and so on methods stores command line options into a Hash.
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# options = {}
+# Gem::OptionParser.new do |parser|
+# parser.on('-a')
+# parser.on('-b NUM', Integer)
+# parser.on('-v', '--verbose')
+# end.parse!(into: options)
+#
+# p options
+#
+# Used:
+#
+# $ ruby optparse-test.rb -a
+# {:a=>true}
+# $ ruby optparse-test.rb -a -v
+# {:a=>true, :verbose=>true}
+# $ ruby optparse-test.rb -a -b 100
+# {:a=>true, :b=>100}
+#
+# === Complete example
+#
+# The following example is a complete Ruby program. You can run it and see the
+# effect of specifying various options. This is probably the best way to learn
+# the features of +optparse+.
+#
+# require 'rubygems/optparse/lib/optparse'
+# require 'rubygems/optparse/lib/optparse/time'
+# require 'ostruct'
+# require 'pp'
+#
+# class OptparseExample
+# Version = '1.0.0'
+#
+# CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
+# CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
+#
+# class ScriptOptions
+# attr_accessor :library, :inplace, :encoding, :transfer_type,
+# :verbose, :extension, :delay, :time, :record_separator,
+# :list
+#
+# def initialize
+# self.library = []
+# self.inplace = false
+# self.encoding = "utf8"
+# self.transfer_type = :auto
+# self.verbose = false
+# end
+#
+# def define_options(parser)
+# parser.banner = "Usage: example.rb [options]"
+# parser.separator ""
+# parser.separator "Specific options:"
+#
+# # add additional options
+# perform_inplace_option(parser)
+# delay_execution_option(parser)
+# execute_at_time_option(parser)
+# specify_record_separator_option(parser)
+# list_example_option(parser)
+# specify_encoding_option(parser)
+# optional_option_argument_with_keyword_completion_option(parser)
+# boolean_verbose_option(parser)
+#
+# parser.separator ""
+# parser.separator "Common options:"
+# # No argument, shows at tail. This will print an options summary.
+# # Try it and see!
+# parser.on_tail("-h", "--help", "Show this message") do
+# puts parser
+# exit
+# end
+# # Another typical switch to print the version.
+# parser.on_tail("--version", "Show version") do
+# puts Version
+# exit
+# end
+# end
+#
+# def perform_inplace_option(parser)
+# # Specifies an optional option argument
+# parser.on("-i", "--inplace [EXTENSION]",
+# "Edit ARGV files in place",
+# "(make backup if EXTENSION supplied)") do |ext|
+# self.inplace = true
+# self.extension = ext || ''
+# self.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
+# end
+# end
+#
+# def delay_execution_option(parser)
+# # Cast 'delay' argument to a Float.
+# parser.on("--delay N", Float, "Delay N seconds before executing") do |n|
+# self.delay = n
+# end
+# end
+#
+# def execute_at_time_option(parser)
+# # Cast 'time' argument to a Time object.
+# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
+# self.time = time
+# end
+# end
+#
+# def specify_record_separator_option(parser)
+# # Cast to octal integer.
+# parser.on("-F", "--irs [OCTAL]", Gem::OptionParser::OctalInteger,
+# "Specify record separator (default \\0)") do |rs|
+# self.record_separator = rs
+# end
+# end
+#
+# def list_example_option(parser)
+# # List of arguments.
+# parser.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
+# self.list = list
+# end
+# end
+#
+# def specify_encoding_option(parser)
+# # Keyword completion. We are specifying a specific set of arguments (CODES
+# # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
+# # the shortest unambiguous text.
+# code_list = (CODE_ALIASES.keys + CODES).join(', ')
+# parser.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
+# "(#{code_list})") do |encoding|
+# self.encoding = encoding
+# end
+# end
+#
+# def optional_option_argument_with_keyword_completion_option(parser)
+# # Optional '--type' option argument with keyword completion.
+# parser.on("--type [TYPE]", [:text, :binary, :auto],
+# "Select transfer type (text, binary, auto)") do |t|
+# self.transfer_type = t
+# end
+# end
+#
+# def boolean_verbose_option(parser)
+# # Boolean switch.
+# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
+# self.verbose = v
+# end
+# end
+# end
+#
+# #
+# # Return a structure describing the options.
+# #
+# def parse(args)
+# # The options specified on the command line will be collected in
+# # *options*.
+#
+# @options = ScriptOptions.new
+# @args = Gem::OptionParser.new do |parser|
+# @options.define_options(parser)
+# parser.parse!(args)
+# end
+# @options
+# end
+#
+# attr_reader :parser, :options
+# end # class OptparseExample
+#
+# example = OptparseExample.new
+# options = example.parse(ARGV)
+# pp options # example.options
+# pp ARGV
+#
+# === Shell Completion
+#
+# For modern shells (e.g. bash, zsh, etc.), you can use shell
+# completion for command line options.
+#
+# === Further documentation
+#
+# The above examples, along with the accompanying
+# {Tutorial}[optparse/tutorial.rdoc],
+# should be enough to learn how to use this class.
+# If you have any questions, file a ticket at http://bugs.ruby-lang.org.
+#
+class Gem::OptionParser
+ Gem::OptionParser::Version = "0.3.0"
+
+ # :stopdoc:
+ NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
+ RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
+ OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
+ # :startdoc:
+
+ #
+ # Keyword completion module. This allows partial arguments to be specified
+ # and resolved against a list of acceptable values.
+ #
+ module Completion
+ def self.regexp(key, icase)
+ Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase)
+ end
+
+ def self.candidate(key, icase = false, pat = nil, &block)
+ pat ||= Completion.regexp(key, icase)
+ candidates = []
+ block.call do |k, *v|
+ (if Regexp === k
+ kn = ""
+ k === key
+ else
+ kn = defined?(k.id2name) ? k.id2name : k
+ pat === kn
+ end) or next
+ v << k if v.empty?
+ candidates << [k, v, kn]
+ end
+ candidates
+ end
+
+ def candidate(key, icase = false, pat = nil)
+ Completion.candidate(key, icase, pat, &method(:each))
+ end
+
+ public
+ def complete(key, icase = false, pat = nil)
+ candidates = candidate(key, icase, pat, &method(:each)).sort_by {|k, v, kn| kn.size}
+ if candidates.size == 1
+ canon, sw, * = candidates[0]
+ elsif candidates.size > 1
+ canon, sw, cn = candidates.shift
+ candidates.each do |k, v, kn|
+ next if sw == v
+ if String === cn and String === kn
+ if cn.rindex(kn, 0)
+ canon, sw, cn = k, v, kn
+ next
+ elsif kn.rindex(cn, 0)
+ next
+ end
+ end
+ throw :ambiguous, key
+ end
+ end
+ if canon
+ block_given? or return key, *sw
+ yield(key, *sw)
+ end
+ end
+
+ def convert(opt = nil, val = nil, *)
+ val
+ end
+ end
+
+
+ #
+ # Map from option/keyword string to object with completion.
+ #
+ class OptionMap < Hash
+ include Completion
+ end
+
+
+ #
+ # Individual switch class. Not important to the user.
+ #
+ # Defined within Switch are several Switch-derived classes: NoArgument,
+ # RequiredArgument, etc.
+ #
+ class Switch
+ attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
+
+ #
+ # Guesses argument style from +arg+. Returns corresponding
+ # Gem::OptionParser::Switch class (OptionalArgument, etc.).
+ #
+ def self.guess(arg)
+ case arg
+ when ""
+ t = self
+ when /\A=?\[/
+ t = Switch::OptionalArgument
+ when /\A\s+\[/
+ t = Switch::PlacedArgument
+ else
+ t = Switch::RequiredArgument
+ end
+ self >= t or incompatible_argument_styles(arg, t)
+ t
+ end
+
+ def self.incompatible_argument_styles(arg, t)
+ raise(ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}",
+ ParseError.filter_backtrace(caller(2)))
+ end
+
+ def self.pattern
+ NilClass
+ end
+
+ def initialize(pattern = nil, conv = nil,
+ short = nil, long = nil, arg = nil,
+ desc = ([] if short or long), block = nil, &_block)
+ raise if Array === pattern
+ block ||= _block
+ @pattern, @conv, @short, @long, @arg, @desc, @block =
+ pattern, conv, short, long, arg, desc, block
+ end
+
+ #
+ # Parses +arg+ and returns rest of +arg+ and matched portion to the
+ # argument pattern. Yields when the pattern doesn't match substring.
+ #
+ def parse_arg(arg) # :nodoc:
+ pattern or return nil, [arg]
+ unless m = pattern.match(arg)
+ yield(InvalidArgument, arg)
+ return arg, []
+ end
+ if String === m
+ m = [s = m]
+ else
+ m = m.to_a
+ s = m[0]
+ return nil, m unless String === s
+ end
+ raise InvalidArgument, arg unless arg.rindex(s, 0)
+ return nil, m if s.length == arg.length
+ yield(InvalidArgument, arg) # didn't match whole arg
+ return arg[s.length..-1], m
+ end
+ private :parse_arg
+
+ #
+ # Parses argument, converts and returns +arg+, +block+ and result of
+ # conversion. Yields at semi-error condition instead of raising an
+ # exception.
+ #
+ def conv_arg(arg, val = []) # :nodoc:
+ if conv
+ val = conv.call(*val)
+ else
+ val = proc {|v| v}.call(*val)
+ end
+ return arg, block, val
+ end
+ private :conv_arg
+
+ #
+ # Produces the summary text. Each line of the summary is yielded to the
+ # block (without newline).
+ #
+ # +sdone+:: Already summarized short style options keyed hash.
+ # +ldone+:: Already summarized long style options keyed hash.
+ # +width+:: Width of left side (option part). In other words, the right
+ # side (description part) starts after +width+ columns.
+ # +max+:: Maximum width of left side -> the options are filled within
+ # +max+ columns.
+ # +indent+:: Prefix string indents all summarized lines.
+ #
+ def summarize(sdone = {}, ldone = {}, width = 1, max = width - 1, indent = "")
+ sopts, lopts = [], [], nil
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
+ return if sopts.empty? and lopts.empty? # completely hidden
+
+ left = [sopts.join(', ')]
+ right = desc.dup
+
+ while s = lopts.shift
+ l = left[-1].length + s.length
+ l += arg.length if left.size == 1 && arg
+ l < max or sopts.empty? or left << +''
+ left[-1] << (left[-1].empty? ? ' ' * 4 : ', ') << s
+ end
+
+ if arg
+ left[0] << (left[1] ? arg.sub(/\A(\[?)=/, '\1') + ',' : arg)
+ end
+ mlen = left.collect {|ss| ss.length}.max.to_i
+ while mlen > width and l = left.shift
+ mlen = left.collect {|ss| ss.length}.max.to_i if l.length == mlen
+ if l.length < width and (r = right[0]) and !r.empty?
+ l = l.to_s.ljust(width) + ' ' + r
+ right.shift
+ end
+ yield(indent + l)
+ end
+
+ while begin l = left.shift; r = right.shift; l or r end
+ l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
+ yield(indent + l)
+ end
+
+ self
+ end
+
+ def add_banner(to) # :nodoc:
+ unless @short or @long
+ s = desc.join
+ to << " [" + s + "]..." unless s.empty?
+ end
+ to
+ end
+
+ def match_nonswitch?(str) # :nodoc:
+ @pattern =~ str unless @short or @long
+ end
+
+ #
+ # Main name of the switch.
+ #
+ def switch_name
+ (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '')
+ end
+
+ def compsys(sdone, ldone) # :nodoc:
+ sopts, lopts = [], []
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
+ return if sopts.empty? and lopts.empty? # completely hidden
+
+ (sopts+lopts).each do |opt|
+ # "(-x -c -r)-l[left justify]"
+ if /^--\[no-\](.+)$/ =~ opt
+ o = $1
+ yield("--#{o}", desc.join(""))
+ yield("--no-#{o}", desc.join(""))
+ else
+ yield("#{opt}", desc.join(""))
+ end
+ end
+ end
+
+ def pretty_print_contents(q) # :nodoc:
+ if @block
+ q.text ":" + @block.source_location.join(":") + ":"
+ first = false
+ else
+ first = true
+ end
+ [@short, @long].each do |list|
+ list.each do |opt|
+ if first
+ q.text ":"
+ first = false
+ end
+ q.breakable
+ q.text opt
+ end
+ end
+ end
+
+ def pretty_print(q) # :nodoc:
+ q.object_group(self) {pretty_print_contents(q)}
+ end
+
+ #
+ # Switch that takes no arguments.
+ #
+ class NoArgument < self
+
+ #
+ # Raises an exception if any arguments given.
+ #
+ def parse(arg, argv)
+ yield(NeedlessArgument, arg) if arg
+ conv_arg(arg)
+ end
+
+ def self.incompatible_argument_styles(*)
+ end
+
+ def self.pattern
+ Object
+ end
+
+ def pretty_head # :nodoc:
+ "NoArgument"
+ end
+ end
+
+ #
+ # Switch that takes an argument.
+ #
+ class RequiredArgument < self
+
+ #
+ # Raises an exception if argument is not present.
+ #
+ def parse(arg, argv)
+ unless arg
+ raise MissingArgument if argv.empty?
+ arg = argv.shift
+ end
+ conv_arg(*parse_arg(arg, &method(:raise)))
+ end
+
+ def pretty_head # :nodoc:
+ "Required"
+ end
+ end
+
+ #
+ # Switch that can omit argument.
+ #
+ class OptionalArgument < self
+
+ #
+ # Parses argument if given, or uses default value.
+ #
+ def parse(arg, argv, &error)
+ if arg
+ conv_arg(*parse_arg(arg, &error))
+ else
+ conv_arg(arg)
+ end
+ end
+
+ def pretty_head # :nodoc:
+ "Optional"
+ end
+ end
+
+ #
+ # Switch that takes an argument, which does not begin with '-' or is '-'.
+ #
+ class PlacedArgument < self
+
+ #
+ # Returns nil if argument is not present or begins with '-' and is not '-'.
+ #
+ def parse(arg, argv, &error)
+ if !(val = arg) and (argv.empty? or /\A-./ =~ (val = argv[0]))
+ return nil, block, nil
+ end
+ opt = (val = parse_arg(val, &error))[1]
+ val = conv_arg(*val)
+ if opt and !arg
+ argv.shift
+ else
+ val[0] = nil
+ end
+ val
+ end
+
+ def pretty_head # :nodoc:
+ "Placed"
+ end
+ end
+ end
+
+ #
+ # Simple option list providing mapping from short and/or long option
+ # string to Gem::OptionParser::Switch and mapping from acceptable argument to
+ # matching pattern and converter pair. Also provides summary feature.
+ #
+ class List
+ # Map from acceptable argument types to pattern and converter pairs.
+ attr_reader :atype
+
+ # Map from short style option switches to actual switch objects.
+ attr_reader :short
+
+ # Map from long style option switches to actual switch objects.
+ attr_reader :long
+
+ # List of all switches and summary string.
+ attr_reader :list
+
+ #
+ # Just initializes all instance variables.
+ #
+ def initialize
+ @atype = {}
+ @short = OptionMap.new
+ @long = OptionMap.new
+ @list = []
+ end
+
+ def pretty_print(q) # :nodoc:
+ q.group(1, "(", ")") do
+ @list.each do |sw|
+ next unless Switch === sw
+ q.group(1, "(" + sw.pretty_head, ")") do
+ sw.pretty_print_contents(q)
+ end
+ end
+ end
+ end
+
+ #
+ # See Gem::OptionParser.accept.
+ #
+ def accept(t, pat = /.*/m, &block)
+ if pat
+ pat.respond_to?(:match) or
+ raise TypeError, "has no `match'", ParseError.filter_backtrace(caller(2))
+ else
+ pat = t if t.respond_to?(:match)
+ end
+ unless block
+ block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
+ end
+ @atype[t] = [pat, block]
+ end
+
+ #
+ # See Gem::OptionParser.reject.
+ #
+ def reject(t)
+ @atype.delete(t)
+ end
+
+ #
+ # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+.
+ #
+ # +sw+:: Gem::OptionParser::Switch instance to be added.
+ # +sopts+:: Short style option list.
+ # +lopts+:: Long style option list.
+ # +nlopts+:: Negated long style options list.
+ #
+ def update(sw, sopts, lopts, nsw = nil, nlopts = nil) # :nodoc:
+ sopts.each {|o| @short[o] = sw} if sopts
+ lopts.each {|o| @long[o] = sw} if lopts
+ nlopts.each {|o| @long[o] = nsw} if nsw and nlopts
+ used = @short.invert.update(@long.invert)
+ @list.delete_if {|o| Switch === o and !used[o]}
+ end
+ private :update
+
+ #
+ # Inserts +switch+ at the head of the list, and associates short, long
+ # and negated long options. Arguments are:
+ #
+ # +switch+:: Gem::OptionParser::Switch instance to be inserted.
+ # +short_opts+:: List of short style options.
+ # +long_opts+:: List of long style options.
+ # +nolong_opts+:: List of long style options with "no-" prefix.
+ #
+ # prepend(switch, short_opts, long_opts, nolong_opts)
+ #
+ def prepend(*args)
+ update(*args)
+ @list.unshift(args[0])
+ end
+
+ #
+ # Appends +switch+ at the tail of the list, and associates short, long
+ # and negated long options. Arguments are:
+ #
+ # +switch+:: Gem::OptionParser::Switch instance to be inserted.
+ # +short_opts+:: List of short style options.
+ # +long_opts+:: List of long style options.
+ # +nolong_opts+:: List of long style options with "no-" prefix.
+ #
+ # append(switch, short_opts, long_opts, nolong_opts)
+ #
+ def append(*args)
+ update(*args)
+ @list.push(args[0])
+ end
+
+ #
+ # Searches +key+ in +id+ list. The result is returned or yielded if a
+ # block is given. If it isn't found, nil is returned.
+ #
+ def search(id, key)
+ if list = __send__(id)
+ val = list.fetch(key) {return nil}
+ block_given? ? yield(val) : val
+ end
+ end
+
+ #
+ # Searches list +id+ for +opt+ and the optional patterns for completion
+ # +pat+. If +icase+ is true, the search is case insensitive. The result
+ # is returned or yielded if a block is given. If it isn't found, nil is
+ # returned.
+ #
+ def complete(id, opt, icase = false, *pat, &block)
+ __send__(id).complete(opt, icase, *pat, &block)
+ end
+
+ def get_candidates(id)
+ yield __send__(id).keys
+ end
+
+ #
+ # Iterates over each option, passing the option to the +block+.
+ #
+ def each_option(&block)
+ list.each(&block)
+ end
+
+ #
+ # Creates the summary table, passing each line to the +block+ (without
+ # newline). The arguments +args+ are passed along to the summarize
+ # method which is called on every option.
+ #
+ def summarize(*args, &block)
+ sum = []
+ list.reverse_each do |opt|
+ if opt.respond_to?(:summarize) # perhaps Gem::OptionParser::Switch
+ s = []
+ opt.summarize(*args) {|l| s << l}
+ sum.concat(s.reverse)
+ elsif !opt or opt.empty?
+ sum << ""
+ elsif opt.respond_to?(:each_line)
+ sum.concat([*opt.each_line].reverse)
+ else
+ sum.concat([*opt.each].reverse)
+ end
+ end
+ sum.reverse_each(&block)
+ end
+
+ def add_banner(to) # :nodoc:
+ list.each do |opt|
+ if opt.respond_to?(:add_banner)
+ opt.add_banner(to)
+ end
+ end
+ to
+ end
+
+ def compsys(*args, &block) # :nodoc:
+ list.each do |opt|
+ if opt.respond_to?(:compsys)
+ opt.compsys(*args, &block)
+ end
+ end
+ end
+ end
+
+ #
+ # Hash with completion search feature. See Gem::OptionParser::Completion.
+ #
+ class CompletingHash < Hash
+ include Completion
+
+ #
+ # Completion for hash key.
+ #
+ def match(key)
+ *values = fetch(key) {
+ raise AmbiguousArgument, catch(:ambiguous) {return complete(key)}
+ }
+ return key, *values
+ end
+ end
+
+ # :stopdoc:
+
+ #
+ # Enumeration of acceptable argument styles. Possible values are:
+ #
+ # NO_ARGUMENT:: The switch takes no arguments. (:NONE)
+ # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED)
+ # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL)
+ #
+ # Use like --switch=argument (long style) or -Xargument (short style). For
+ # short style, only portion matched to argument pattern is treated as
+ # argument.
+ #
+ ArgumentStyle = {}
+ NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument}
+ RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument}
+ OptionalArgument.each {|el| ArgumentStyle[el] = Switch::OptionalArgument}
+ ArgumentStyle.freeze
+
+ #
+ # Switches common used such as '--', and also provides default
+ # argument classes
+ #
+ DefaultList = List.new
+ DefaultList.short['-'] = Switch::NoArgument.new {}
+ DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
+
+
+ COMPSYS_HEADER = <<'XXX' # :nodoc:
+
+typeset -A opt_args
+local context state line
+
+_arguments -s -S \
+XXX
+
+ def compsys(to, name = File.basename($0)) # :nodoc:
+ to << "#compdef #{name}\n"
+ to << COMPSYS_HEADER
+ visit(:compsys, {}, {}) {|o, d|
+ to << %Q[ "#{o}[#{d.gsub(/[\"\[\]]/, '\\\\\&')}]" \\\n]
+ }
+ to << " '*:file:_files' && return 0\n"
+ end
+
+ #
+ # Default options for ARGV, which never appear in option summary.
+ #
+ Officious = {}
+
+ #
+ # --help
+ # Shows option summary.
+ #
+ Officious['help'] = proc do |parser|
+ Switch::NoArgument.new do |arg|
+ puts parser.help
+ exit
+ end
+ end
+
+ #
+ # --*-completion-bash=WORD
+ # Shows candidates for command line completion.
+ #
+ Officious['*-completion-bash'] = proc do |parser|
+ Switch::RequiredArgument.new do |arg|
+ puts parser.candidate(arg)
+ exit
+ end
+ end
+
+ #
+ # --*-completion-zsh[=NAME:FILE]
+ # Creates zsh completion file.
+ #
+ Officious['*-completion-zsh'] = proc do |parser|
+ Switch::OptionalArgument.new do |arg|
+ parser.compsys(STDOUT, arg)
+ exit
+ end
+ end
+
+ #
+ # --version
+ # Shows version string if Version is defined.
+ #
+ Officious['version'] = proc do |parser|
+ Switch::OptionalArgument.new do |pkg|
+ if pkg
+ begin
+ require 'rubygems/optparse/lib/optparse/version'
+ rescue LoadError
+ else
+ show_version(*pkg.split(/,/)) or
+ abort("#{parser.program_name}: no version found in package #{pkg}")
+ exit
+ end
+ end
+ v = parser.ver or abort("#{parser.program_name}: version unknown")
+ puts v
+ exit
+ end
+ end
+
+ # :startdoc:
+
+ #
+ # Class methods
+ #
+
+ #
+ # Initializes a new instance and evaluates the optional block in context
+ # of the instance. Arguments +args+ are passed to #new, see there for
+ # description of parameters.
+ #
+ # This method is *deprecated*, its behavior corresponds to the older #new
+ # method.
+ #
+ def self.with(*args, &block)
+ opts = new(*args)
+ opts.instance_eval(&block)
+ opts
+ end
+
+ #
+ # Returns an incremented value of +default+ according to +arg+.
+ #
+ def self.inc(arg, default = nil)
+ case arg
+ when Integer
+ arg.nonzero?
+ when nil
+ default.to_i + 1
+ end
+ end
+ def inc(*args)
+ self.class.inc(*args)
+ end
+
+ #
+ # Initializes the instance and yields itself if called with a block.
+ #
+ # +banner+:: Banner message.
+ # +width+:: Summary width.
+ # +indent+:: Summary indent.
+ #
+ def initialize(banner = nil, width = 32, indent = ' ' * 4)
+ @stack = [DefaultList, List.new, List.new]
+ @program_name = nil
+ @banner = banner
+ @summary_width = width
+ @summary_indent = indent
+ @default_argv = ARGV
+ @require_exact = false
+ @raise_unknown = true
+ add_officious
+ yield self if block_given?
+ end
+
+ def add_officious # :nodoc:
+ list = base()
+ Officious.each do |opt, block|
+ list.long[opt] ||= block.call(self)
+ end
+ end
+
+ #
+ # Terminates option parsing. Optional parameter +arg+ is a string pushed
+ # back to be the first non-option argument.
+ #
+ def terminate(arg = nil)
+ self.class.terminate(arg)
+ end
+ def self.terminate(arg = nil)
+ throw :terminate, arg
+ end
+
+ @stack = [DefaultList]
+ def self.top() DefaultList end
+
+ #
+ # Directs to accept specified class +t+. The argument string is passed to
+ # the block in which it should be converted to the desired class.
+ #
+ # +t+:: Argument class specifier, any object including Class.
+ # +pat+:: Pattern for argument, defaults to +t+ if it responds to match.
+ #
+ # accept(t, pat, &block)
+ #
+ def accept(*args, &blk) top.accept(*args, &blk) end
+ #
+ # See #accept.
+ #
+ def self.accept(*args, &blk) top.accept(*args, &blk) end
+
+ #
+ # Directs to reject specified class argument.
+ #
+ # +t+:: Argument class specifier, any object including Class.
+ #
+ # reject(t)
+ #
+ def reject(*args, &blk) top.reject(*args, &blk) end
+ #
+ # See #reject.
+ #
+ def self.reject(*args, &blk) top.reject(*args, &blk) end
+
+ #
+ # Instance methods
+ #
+
+ # Heading banner preceding summary.
+ attr_writer :banner
+
+ # Program name to be emitted in error message and default banner,
+ # defaults to $0.
+ attr_writer :program_name
+
+ # Width for option list portion of summary. Must be Numeric.
+ attr_accessor :summary_width
+
+ # Indentation for summary. Must be String (or have + String method).
+ attr_accessor :summary_indent
+
+ # Strings to be parsed in default.
+ attr_accessor :default_argv
+
+ # Whether to require that options match exactly (disallows providing
+ # abbreviated long option as short option).
+ attr_accessor :require_exact
+
+ # Whether to raise at unknown option.
+ attr_accessor :raise_unknown
+
+ #
+ # Heading banner preceding summary.
+ #
+ def banner
+ unless @banner
+ @banner = +"Usage: #{program_name} [options]"
+ visit(:add_banner, @banner)
+ end
+ @banner
+ end
+
+ #
+ # Program name to be emitted in error message and default banner, defaults
+ # to $0.
+ #
+ def program_name
+ @program_name || File.basename($0, '.*')
+ end
+
+ # for experimental cascading :-)
+ alias set_banner banner=
+ alias set_program_name program_name=
+ alias set_summary_width summary_width=
+ alias set_summary_indent summary_indent=
+
+ # Version
+ attr_writer :version
+ # Release code
+ attr_writer :release
+
+ #
+ # Version
+ #
+ def version
+ (defined?(@version) && @version) || (defined?(::Version) && ::Version)
+ end
+
+ #
+ # Release code
+ #
+ def release
+ (defined?(@release) && @release) || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE)
+ end
+
+ #
+ # Returns version string from program_name, version and release.
+ #
+ def ver
+ if v = version
+ str = +"#{program_name} #{[v].join('.')}"
+ str << " (#{v})" if v = release
+ str
+ end
+ end
+
+ def warn(mesg = $!)
+ super("#{program_name}: #{mesg}")
+ end
+
+ def abort(mesg = $!)
+ super("#{program_name}: #{mesg}")
+ end
+
+ #
+ # Subject of #on / #on_head, #accept / #reject
+ #
+ def top
+ @stack[-1]
+ end
+
+ #
+ # Subject of #on_tail.
+ #
+ def base
+ @stack[1]
+ end
+
+ #
+ # Pushes a new List.
+ #
+ def new
+ @stack.push(List.new)
+ if block_given?
+ yield self
+ else
+ self
+ end
+ end
+
+ #
+ # Removes the last List.
+ #
+ def remove
+ @stack.pop
+ end
+
+ #
+ # Puts option summary into +to+ and returns +to+. Yields each line if
+ # a block is given.
+ #
+ # +to+:: Output destination, which must have method <<. Defaults to [].
+ # +width+:: Width of left side, defaults to @summary_width.
+ # +max+:: Maximum length allowed for left side, defaults to +width+ - 1.
+ # +indent+:: Indentation, defaults to @summary_indent.
+ #
+ def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
+ nl = "\n"
+ blk ||= proc {|l| to << (l.index(nl, -1) ? l : l + nl)}
+ visit(:summarize, {}, {}, width, max, indent, &blk)
+ to
+ end
+
+ #
+ # Returns option summary string.
+ #
+ def help; summarize("#{banner}".sub(/\n?\z/, "\n")) end
+ alias to_s help
+
+ def pretty_print(q) # :nodoc:
+ q.object_group(self) do
+ first = true
+ if @stack.size > 2
+ @stack.each_with_index do |s, i|
+ next if i < 2
+ next if s.list.empty?
+ if first
+ first = false
+ q.text ":"
+ end
+ q.breakable
+ s.pretty_print(q)
+ end
+ end
+ end
+ end
+
+ def inspect # :nodoc:
+ require 'pp'
+ pretty_print_inspect
+ end
+
+ #
+ # Returns option summary list.
+ #
+ def to_a; summarize("#{banner}".split(/^/)) end
+
+ #
+ # Checks if an argument is given twice, in which case an ArgumentError is
+ # raised. Called from Gem::OptionParser#switch only.
+ #
+ # +obj+:: New argument.
+ # +prv+:: Previously specified argument.
+ # +msg+:: Exception message.
+ #
+ def notwice(obj, prv, msg) # :nodoc:
+ unless !prv or prv == obj
+ raise(ArgumentError, "argument #{msg} given twice: #{obj}",
+ ParseError.filter_backtrace(caller(2)))
+ end
+ obj
+ end
+ private :notwice
+
+ SPLAT_PROC = proc {|*a| a.length <= 1 ? a.first : a} # :nodoc:
+
+ # :call-seq:
+ # make_switch(params, block = nil)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def make_switch(opts, block = nil)
+ short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], []
+ ldesc, sdesc, desc, arg = [], [], []
+ default_style = Switch::NoArgument
+ default_pattern = nil
+ klass = nil
+ q, a = nil
+ has_arg = false
+
+ opts.each do |o|
+ # argument class
+ next if search(:atype, o) do |pat, c|
+ klass = notwice(o, klass, 'type')
+ if not_style and not_style != Switch::NoArgument
+ not_pattern, not_conv = pat, c
+ else
+ default_pattern, conv = pat, c
+ end
+ end
+
+ # directly specified pattern(any object possible to match)
+ if (!(String === o || Symbol === o)) and o.respond_to?(:match)
+ pattern = notwice(o, pattern, 'pattern')
+ if pattern.respond_to?(:convert)
+ conv = pattern.method(:convert).to_proc
+ else
+ conv = SPLAT_PROC
+ end
+ next
+ end
+
+ # anything others
+ case o
+ when Proc, Method
+ block = notwice(o, block, 'block')
+ when Array, Hash
+ case pattern
+ when CompletingHash
+ when nil
+ pattern = CompletingHash.new
+ conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
+ else
+ raise ArgumentError, "argument pattern given twice"
+ end
+ o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
+ when Module
+ raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4))
+ when *ArgumentStyle.keys
+ style = notwice(ArgumentStyle[o], style, 'style')
+ when /^--no-([^\[\]=\s]*)(.+)?/
+ q, a = $1, $2
+ o = notwice(a ? Object : TrueClass, klass, 'type')
+ not_pattern, not_conv = search(:atype, o) unless not_style
+ not_style = (not_style || default_style).guess(arg = a) if a
+ default_style = Switch::NoArgument
+ default_pattern, conv = search(:atype, FalseClass) unless default_pattern
+ ldesc << "--no-#{q}"
+ (q = q.downcase).tr!('_', '-')
+ long << "no-#{q}"
+ nolong << q
+ when /^--\[no-\]([^\[\]=\s]*)(.+)?/
+ q, a = $1, $2
+ o = notwice(a ? Object : TrueClass, klass, 'type')
+ if a
+ default_style = default_style.guess(arg = a)
+ default_pattern, conv = search(:atype, o) unless default_pattern
+ end
+ ldesc << "--[no-]#{q}"
+ (o = q.downcase).tr!('_', '-')
+ long << o
+ not_pattern, not_conv = search(:atype, FalseClass) unless not_style
+ not_style = Switch::NoArgument
+ nolong << "no-#{o}"
+ when /^--([^\[\]=\s]*)(.+)?/
+ q, a = $1, $2
+ if a
+ o = notwice(NilClass, klass, 'type')
+ default_style = default_style.guess(arg = a)
+ default_pattern, conv = search(:atype, o) unless default_pattern
+ end
+ ldesc << "--#{q}"
+ (o = q.downcase).tr!('_', '-')
+ long << o
+ when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
+ q, a = $1, $2
+ o = notwice(Object, klass, 'type')
+ if a
+ default_style = default_style.guess(arg = a)
+ default_pattern, conv = search(:atype, o) unless default_pattern
+ else
+ has_arg = true
+ end
+ sdesc << "-#{q}"
+ short << Regexp.new(q)
+ when /^-(.)(.+)?/
+ q, a = $1, $2
+ if a
+ o = notwice(NilClass, klass, 'type')
+ default_style = default_style.guess(arg = a)
+ default_pattern, conv = search(:atype, o) unless default_pattern
+ end
+ sdesc << "-#{q}"
+ short << q
+ when /^=/
+ style = notwice(default_style.guess(arg = o), style, 'style')
+ default_pattern, conv = search(:atype, Object) unless default_pattern
+ else
+ desc.push(o) if o && !o.empty?
+ end
+ end
+
+ default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
+ if !(short.empty? and long.empty?)
+ if has_arg and default_style == Switch::NoArgument
+ default_style = Switch::RequiredArgument
+ end
+ s = (style || default_style).new(pattern || default_pattern,
+ conv, sdesc, ldesc, arg, desc, block)
+ elsif !block
+ if style or pattern
+ raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
+ end
+ s = desc
+ else
+ short << pattern
+ s = (style || default_style).new(pattern,
+ conv, nil, nil, arg, desc, block)
+ end
+ return s, short, long,
+ (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
+ nolong
+ end
+
+ # :call-seq:
+ # define(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def define(*opts, &block)
+ top.append(*(sw = make_switch(opts, block)))
+ sw[0]
+ end
+
+ # :call-seq:
+ # on(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def on(*opts, &block)
+ define(*opts, &block)
+ self
+ end
+ alias def_option define
+
+ # :call-seq:
+ # define_head(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def define_head(*opts, &block)
+ top.prepend(*(sw = make_switch(opts, block)))
+ sw[0]
+ end
+
+ # :call-seq:
+ # on_head(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ # The new option is added at the head of the summary.
+ #
+ def on_head(*opts, &block)
+ define_head(*opts, &block)
+ self
+ end
+ alias def_head_option define_head
+
+ # :call-seq:
+ # define_tail(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def define_tail(*opts, &block)
+ base.append(*(sw = make_switch(opts, block)))
+ sw[0]
+ end
+
+ #
+ # :call-seq:
+ # on_tail(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ # The new option is added at the tail of the summary.
+ #
+ def on_tail(*opts, &block)
+ define_tail(*opts, &block)
+ self
+ end
+ alias def_tail_option define_tail
+
+ #
+ # Add separator in summary.
+ #
+ def separator(string)
+ top.append(string, nil, nil)
+ end
+
+ #
+ # Parses command line arguments +argv+ in order. When a block is given,
+ # each non-option argument is yielded. When optional +into+ keyword
+ # argument is provided, the parsed option values are stored there via
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
+ # similar object).
+ #
+ # Returns the rest of +argv+ left unparsed.
+ #
+ def order(*argv, into: nil, &nonopt)
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
+ order!(argv, into: into, &nonopt)
+ end
+
+ #
+ # Same as #order, but removes switches destructively.
+ # Non-option arguments remain in +argv+.
+ #
+ def order!(argv = default_argv, into: nil, &nonopt)
+ setter = ->(name, val) {into[name.to_sym] = val} if into
+ parse_in_order(argv, setter, &nonopt)
+ end
+
+ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
+ opt, arg, val, rest = nil
+ nonopt ||= proc {|a| throw :terminate, a}
+ argv.unshift(arg) if arg = catch(:terminate) {
+ while arg = argv.shift
+ case arg
+ # long option
+ when /\A--([^=]*)(?:=(.*))?/m
+ opt, rest = $1, $2
+ opt.tr!('_', '-')
+ begin
+ sw, = complete(:long, opt, true)
+ if require_exact && !sw.long.include?(arg)
+ throw :terminate, arg unless raise_unknown
+ raise InvalidOption, arg
+ end
+ rescue ParseError
+ throw :terminate, arg unless raise_unknown
+ raise $!.set_option(arg, true)
+ end
+ begin
+ opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
+ val = cb.call(val) if cb
+ setter.call(sw.switch_name, val) if setter
+ rescue ParseError
+ raise $!.set_option(arg, rest)
+ end
+
+ # short option
+ when /\A-(.)((=).*|.+)?/m
+ eq, rest, opt = $3, $2, $1
+ has_arg, val = eq, rest
+ begin
+ sw, = search(:short, opt)
+ unless sw
+ begin
+ sw, = complete(:short, opt)
+ # short option matched.
+ val = arg.delete_prefix('-')
+ has_arg = true
+ rescue InvalidOption
+ raise if require_exact
+ # if no short options match, try completion with long
+ # options.
+ sw, = complete(:long, opt)
+ eq ||= !rest
+ end
+ end
+ rescue ParseError
+ throw :terminate, arg unless raise_unknown
+ raise $!.set_option(arg, true)
+ end
+ begin
+ opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
+ rescue ParseError
+ raise $!.set_option(arg, arg.length > 2)
+ else
+ raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
+ end
+ begin
+ argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
+ val = cb.call(val) if cb
+ setter.call(sw.switch_name, val) if setter
+ rescue ParseError
+ raise $!.set_option(arg, arg.length > 2)
+ end
+
+ # non-option argument
+ else
+ catch(:prune) do
+ visit(:each_option) do |sw0|
+ sw = sw0
+ sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg)
+ end
+ nonopt.call(arg)
+ end
+ end
+ end
+
+ nil
+ }
+
+ visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
+
+ argv
+ end
+ private :parse_in_order
+
+ #
+ # Parses command line arguments +argv+ in permutation mode and returns
+ # list of non-option arguments. When optional +into+ keyword
+ # argument is provided, the parsed option values are stored there via
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
+ # similar object).
+ #
+ def permute(*argv, into: nil)
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
+ permute!(argv, into: into)
+ end
+
+ #
+ # Same as #permute, but removes switches destructively.
+ # Non-option arguments remain in +argv+.
+ #
+ def permute!(argv = default_argv, into: nil)
+ nonopts = []
+ order!(argv, into: into, &nonopts.method(:<<))
+ argv[0, 0] = nonopts
+ argv
+ end
+
+ #
+ # Parses command line arguments +argv+ in order when environment variable
+ # POSIXLY_CORRECT is set, and in permutation mode otherwise.
+ # When optional +into+ keyword argument is provided, the parsed option
+ # values are stored there via <code>[]=</code> method (so it can be Hash,
+ # or OpenStruct, or other similar object).
+ #
+ def parse(*argv, into: nil)
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
+ parse!(argv, into: into)
+ end
+
+ #
+ # Same as #parse, but removes switches destructively.
+ # Non-option arguments remain in +argv+.
+ #
+ def parse!(argv = default_argv, into: nil)
+ if ENV.include?('POSIXLY_CORRECT')
+ order!(argv, into: into)
+ else
+ permute!(argv, into: into)
+ end
+ end
+
+ #
+ # Wrapper method for getopts.rb.
+ #
+ # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option")
+ # # 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)
+ argv = Array === args.first ? args.shift : default_argv
+ single_options, *long_options = *args
+
+ result = {}
+
+ single_options.scan(/(.)(:)?/) do |opt, val|
+ if val
+ result[opt] = nil
+ define("-#{opt} VAL")
+ else
+ result[opt] = false
+ define("-#{opt}")
+ end
+ end if single_options
+
+ long_options.each do |arg|
+ arg, desc = arg.split(';', 2)
+ opt, val = arg.split(':', 2)
+ if val
+ result[opt] = val.empty? ? nil : val
+ define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
+ else
+ result[opt] = false
+ define("--#{opt}", *[desc].compact)
+ end
+ end
+
+ parse_in_order(argv, result.method(:[]=))
+ result
+ end
+
+ #
+ # See #getopts.
+ #
+ def self.getopts(*args)
+ new.getopts(*args)
+ end
+
+ #
+ # Traverses @stack, sending each element method +id+ with +args+ and
+ # +block+.
+ #
+ def visit(id, *args, &block) # :nodoc:
+ @stack.reverse_each do |el|
+ el.__send__(id, *args, &block)
+ end
+ nil
+ end
+ private :visit
+
+ #
+ # Searches +key+ in @stack for +id+ hash and returns or yields the result.
+ #
+ def search(id, key) # :nodoc:
+ block_given = block_given?
+ visit(:search, id, key) do |k|
+ return block_given ? yield(k) : k
+ end
+ end
+ private :search
+
+ #
+ # Completes shortened long style option switch and returns pair of
+ # canonical switch and switch descriptor Gem::OptionParser::Switch.
+ #
+ # +typ+:: Searching table.
+ # +opt+:: Searching key.
+ # +icase+:: Search case insensitive if true.
+ # +pat+:: Optional pattern for completion.
+ #
+ def complete(typ, opt, icase = false, *pat) # :nodoc:
+ if pat.empty?
+ search(typ, opt) {|sw| return [sw, opt]} # exact match or...
+ end
+ ambiguous = catch(:ambiguous) {
+ visit(:complete, typ, opt, icase, *pat) {|o, *sw| return sw}
+ }
+ exc = ambiguous ? AmbiguousOption : InvalidOption
+ raise exc.new(opt, additional: self.method(:additional_message).curry[typ])
+ end
+ private :complete
+
+ #
+ # Returns additional info.
+ #
+ def additional_message(typ, opt)
+ return unless typ and opt and defined?(DidYouMean::SpellChecker)
+ all_candidates = []
+ visit(:get_candidates, typ) do |candidates|
+ all_candidates.concat(candidates)
+ end
+ all_candidates.select! {|cand| cand.is_a?(String) }
+ checker = DidYouMean::SpellChecker.new(dictionary: all_candidates)
+ DidYouMean.formatter.message_for(all_candidates & checker.correct(opt))
+ end
+
+ def candidate(word)
+ list = []
+ case word
+ when '-'
+ long = short = true
+ when /\A--/
+ word, arg = word.split(/=/, 2)
+ argpat = Completion.regexp(arg, false) if arg and !arg.empty?
+ long = true
+ when /\A-/
+ short = true
+ end
+ pat = Completion.regexp(word, long)
+ visit(:each_option) do |opt|
+ next unless Switch === opt
+ opts = (long ? opt.long : []) + (short ? opt.short : [])
+ opts = Completion.candidate(word, true, pat, &opts.method(:each)).map(&:first) if pat
+ if /\A=/ =~ opt.arg
+ opts.map! {|sw| sw + "="}
+ if arg and CompletingHash === opt.pattern
+ if opts = opt.pattern.candidate(arg, false, argpat)
+ opts.map!(&:last)
+ end
+ end
+ end
+ list.concat(opts)
+ end
+ list
+ end
+
+ #
+ # Loads options from file names as +filename+. Does nothing when the file
+ # is not present. Returns whether successfully loaded.
+ #
+ # +filename+ defaults to basename of the program without suffix in a
+ # directory ~/.options, then the basename with '.options' suffix
+ # under XDG and Haiku standard places.
+ #
+ # The optional +into+ keyword argument works exactly like that accepted in
+ # method #parse.
+ #
+ def load(filename = nil, into: nil)
+ unless filename
+ basename = File.basename($0, '.*')
+ return true if load(File.expand_path(basename, '~/.options'), into: into) rescue nil
+ basename << ".options"
+ return [
+ # XDG
+ ENV['XDG_CONFIG_HOME'],
+ '~/.config',
+ *ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
+
+ # Haiku
+ '~/config/settings',
+ ].any? {|dir|
+ next if !dir or dir.empty?
+ load(File.expand_path(basename, dir), into: into) rescue nil
+ }
+ end
+ begin
+ parse(*File.readlines(filename, chomp: true), into: into)
+ true
+ rescue Errno::ENOENT, Errno::ENOTDIR
+ false
+ end
+ end
+
+ #
+ # Parses environment variable +env+ or its uppercase with splitting like a
+ # shell.
+ #
+ # +env+ defaults to the basename of the program.
+ #
+ def environment(env = File.basename($0, '.*'))
+ env = ENV[env] || ENV[env.upcase] or return
+ require 'shellwords'
+ parse(*Shellwords.shellwords(env))
+ end
+
+ #
+ # Acceptable argument classes
+ #
+
+ #
+ # Any string and no conversion. This is fall-back.
+ #
+ accept(Object) {|s,|s or s.nil?}
+
+ accept(NilClass) {|s,|s}
+
+ #
+ # Any non-empty string, and no conversion.
+ #
+ accept(String, /.+/m) {|s,*|s}
+
+ #
+ # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal
+ # for 0x, and decimal for others; with optional sign prefix. Converts to
+ # Integer.
+ #
+ decimal = '\d+(?:_\d+)*'
+ binary = 'b[01]+(?:_[01]+)*'
+ hex = 'x[\da-f]+(?:_[\da-f]+)*'
+ octal = "0(?:[0-7]+(?:_[0-7]+)*|#{binary}|#{hex})?"
+ integer = "#{octal}|#{decimal}"
+
+ accept(Integer, %r"\A[-+]?(?:#{integer})\z"io) {|s,|
+ begin
+ Integer(s)
+ rescue ArgumentError
+ raise Gem::OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Float number format, and converts to Float.
+ #
+ float = "(?:#{decimal}(?=(.)?)(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?"
+ floatpat = %r"\A[-+]?#{float}\z"io
+ accept(Float, floatpat) {|s,| s.to_f if s}
+
+ #
+ # Generic numeric format, converts to Integer for integer format, Float
+ # for float format, and Rational for rational format.
+ #
+ real = "[-+]?(?:#{octal}|#{float})"
+ accept(Numeric, /\A(#{real})(?:\/(#{real}))?\z/io) {|s, d, f, n,|
+ if n
+ Rational(d, n)
+ elsif f
+ Float(s)
+ else
+ Integer(s)
+ end
+ }
+
+ #
+ # Decimal integer format, to be converted to Integer.
+ #
+ DecimalInteger = /\A[-+]?#{decimal}\z/io
+ accept(DecimalInteger, DecimalInteger) {|s,|
+ begin
+ Integer(s, 10)
+ rescue ArgumentError
+ raise Gem::OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Ruby/C like octal/hexadecimal/binary integer format, to be converted to
+ # Integer.
+ #
+ OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))\z/io
+ accept(OctalInteger, OctalInteger) {|s,|
+ begin
+ Integer(s, 8)
+ rescue ArgumentError
+ raise Gem::OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Decimal integer/float number format, to be converted to Integer for
+ # integer format, Float for float format.
+ #
+ DecimalNumeric = floatpat # decimal integer is allowed as float also.
+ accept(DecimalNumeric, floatpat) {|s, f|
+ begin
+ if f
+ Float(s)
+ else
+ Integer(s)
+ end
+ rescue ArgumentError
+ raise Gem::OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Boolean switch, which means whether it is present or not, whether it is
+ # absent or not with prefix no-, or it takes an argument
+ # yes/no/true/false/+/-.
+ #
+ yesno = CompletingHash.new
+ %w[- no false].each {|el| yesno[el] = false}
+ %w[+ yes true].each {|el| yesno[el] = true}
+ yesno['nil'] = false # should be nil?
+ accept(TrueClass, yesno) {|arg, val| val == nil or val}
+ #
+ # Similar to TrueClass, but defaults to false.
+ #
+ accept(FalseClass, yesno) {|arg, val| val != nil and val}
+
+ #
+ # List of strings separated by ",".
+ #
+ accept(Array) do |s, |
+ if s
+ s = s.split(',').collect {|ss| ss unless ss.empty?}
+ end
+ s
+ end
+
+ #
+ # Regular expression with options.
+ #
+ accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o|
+ f = 0
+ if o
+ f |= Regexp::IGNORECASE if /i/ =~ o
+ f |= Regexp::MULTILINE if /m/ =~ o
+ f |= Regexp::EXTENDED if /x/ =~ o
+ k = o.delete("imx")
+ k = nil if k.empty?
+ end
+ Regexp.new(s || all, f, k)
+ end
+
+ #
+ # Exceptions
+ #
+
+ #
+ # Base class of exceptions from Gem::OptionParser.
+ #
+ class ParseError < RuntimeError
+ # Reason which caused the error.
+ Reason = 'parse error'
+
+ def initialize(*args, additional: nil)
+ @additional = additional
+ @arg0, = args
+ @args = args
+ @reason = nil
+ end
+
+ attr_reader :args
+ attr_writer :reason
+ attr_accessor :additional
+
+ #
+ # Pushes back erred argument(s) to +argv+.
+ #
+ def recover(argv)
+ argv[0, 0] = @args
+ argv
+ end
+
+ def self.filter_backtrace(array)
+ unless $DEBUG
+ array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
+ end
+ array
+ end
+
+ def set_backtrace(array)
+ super(self.class.filter_backtrace(array))
+ end
+
+ def set_option(opt, eq)
+ if eq
+ @args[0] = opt
+ else
+ @args.unshift(opt)
+ end
+ self
+ end
+
+ #
+ # Returns error reason. Override this for I18N.
+ #
+ def reason
+ @reason || self.class::Reason
+ end
+
+ def inspect
+ "#<#{self.class}: #{args.join(' ')}>"
+ end
+
+ #
+ # Default stringizing method to emit standard error message.
+ #
+ def message
+ "#{reason}: #{args.join(' ')}#{additional[@arg0] if additional}"
+ end
+
+ alias to_s message
+ end
+
+ #
+ # Raises when ambiguously completable string is encountered.
+ #
+ class AmbiguousOption < ParseError
+ const_set(:Reason, 'ambiguous option')
+ end
+
+ #
+ # Raises when there is an argument for a switch which takes no argument.
+ #
+ class NeedlessArgument < ParseError
+ const_set(:Reason, 'needless argument')
+ end
+
+ #
+ # Raises when a switch with mandatory argument has no argument.
+ #
+ class MissingArgument < ParseError
+ const_set(:Reason, 'missing argument')
+ end
+
+ #
+ # Raises when switch is undefined.
+ #
+ class InvalidOption < ParseError
+ const_set(:Reason, 'invalid option')
+ end
+
+ #
+ # Raises when the given argument does not match required format.
+ #
+ class InvalidArgument < ParseError
+ const_set(:Reason, 'invalid argument')
+ end
+
+ #
+ # Raises when the given argument word can't be completed uniquely.
+ #
+ class AmbiguousArgument < InvalidArgument
+ const_set(:Reason, 'ambiguous argument')
+ end
+
+ #
+ # Miscellaneous
+ #
+
+ #
+ # Extends command line arguments array (ARGV) to parse itself.
+ #
+ module Arguable
+
+ #
+ # Sets Gem::OptionParser object, when +opt+ is +false+ or +nil+, methods
+ # Gem::OptionParser::Arguable#options and Gem::OptionParser::Arguable#options= are
+ # undefined. Thus, there is no ways to access the Gem::OptionParser object
+ # via the receiver object.
+ #
+ def options=(opt)
+ unless @optparse = opt
+ class << self
+ undef_method(:options)
+ undef_method(:options=)
+ end
+ end
+ end
+
+ #
+ # Actual Gem::OptionParser object, automatically created if nonexistent.
+ #
+ # If called with a block, yields the Gem::OptionParser object and returns the
+ # result of the block. If an Gem::OptionParser::ParseError exception occurs
+ # in the block, it is rescued, a error message printed to STDERR and
+ # +nil+ returned.
+ #
+ def options
+ @optparse ||= Gem::OptionParser.new
+ @optparse.default_argv = self
+ block_given? or return @optparse
+ begin
+ yield @optparse
+ rescue ParseError
+ @optparse.warn $!
+ nil
+ end
+ end
+
+ #
+ # Parses +self+ destructively in order and returns +self+ containing the
+ # rest arguments left unparsed.
+ #
+ def order!(&blk) options.order!(self, &blk) end
+
+ #
+ # Parses +self+ destructively in permutation mode and returns +self+
+ # containing the rest arguments left unparsed.
+ #
+ def permute!() options.permute!(self) end
+
+ #
+ # Parses +self+ destructively and returns +self+ containing the
+ # rest arguments left unparsed.
+ #
+ def parse!() options.parse!(self) end
+
+ #
+ # Substitution of getopts is possible as follows. Also see
+ # Gem::OptionParser#getopts.
+ #
+ # def getopts(*args)
+ # ($OPT = ARGV.getopts(*args)).each do |opt, val|
+ # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val"
+ # end
+ # rescue Gem::OptionParser::ParseError
+ # end
+ #
+ def getopts(*args)
+ options.getopts(self, *args)
+ end
+
+ #
+ # Initializes instance variable.
+ #
+ def self.extend_object(obj)
+ super
+ obj.instance_eval {@optparse = nil}
+ end
+ def initialize(*args)
+ super
+ @optparse = nil
+ end
+ end
+
+ #
+ # Acceptable argument classes. Now contains DecimalInteger, OctalInteger
+ # and DecimalNumeric. See Acceptable argument classes (in source code).
+ #
+ module Acceptables
+ const_set(:DecimalInteger, Gem::OptionParser::DecimalInteger)
+ const_set(:OctalInteger, Gem::OptionParser::OctalInteger)
+ const_set(:DecimalNumeric, Gem::OptionParser::DecimalNumeric)
+ end
+end
+
+# ARGV is arguable by Gem::OptionParser
+ARGV.extend(Gem::OptionParser::Arguable)
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/ac.rb b/lib/rubygems/optparse/lib/optparse/ac.rb
index e84d01bf91..e84d01bf91 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/ac.rb
+++ b/lib/rubygems/optparse/lib/optparse/ac.rb
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/date.rb b/lib/rubygems/optparse/lib/optparse/date.rb
index d9a9f4f48a..d9a9f4f48a 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/date.rb
+++ b/lib/rubygems/optparse/lib/optparse/date.rb
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/kwargs.rb b/lib/rubygems/optparse/lib/optparse/kwargs.rb
index 6987a5ed62..6987a5ed62 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/kwargs.rb
+++ b/lib/rubygems/optparse/lib/optparse/kwargs.rb
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/shellwords.rb b/lib/rubygems/optparse/lib/optparse/shellwords.rb
index d47ad60255..d47ad60255 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/shellwords.rb
+++ b/lib/rubygems/optparse/lib/optparse/shellwords.rb
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/time.rb b/lib/rubygems/optparse/lib/optparse/time.rb
index c59e1e4ced..c59e1e4ced 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/time.rb
+++ b/lib/rubygems/optparse/lib/optparse/time.rb
diff --git a/lib/rubygems/optparse/lib/optparse/uri.rb b/lib/rubygems/optparse/lib/optparse/uri.rb
new file mode 100644
index 0000000000..664d7f2af4
--- /dev/null
+++ b/lib/rubygems/optparse/lib/optparse/uri.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: false
+# -*- ruby -*-
+
+require_relative '../optparse'
+require 'uri'
+
+Gem::OptionParser.accept(URI) {|s,| URI.parse(s) if s}
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/version.rb b/lib/rubygems/optparse/lib/optparse/version.rb
index 5d79e9db44..5d79e9db44 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/version.rb
+++ b/lib/rubygems/optparse/lib/optparse/version.rb
diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
index c855423ed7..4672866985 100644
--- a/lib/rubygems/package.rb
+++ b/lib/rubygems/package.rb
@@ -1,12 +1,10 @@
# 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"
require_relative "user_interaction"
@@ -58,9 +56,9 @@ class Gem::Package
def initialize(message, source = nil)
if source
- @path = source.is_a?(String) ? source : source.path
+ @path = source.path
- message += " in #{path}" if path
+ message = message + " in #{path}" if path
end
super message
@@ -69,13 +67,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
@@ -154,7 +154,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
@@ -186,7 +186,7 @@ class Gem::Package
end
end
- [spec, metadata]
+ return spec, metadata
end
##
@@ -229,7 +229,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
@@ -241,7 +241,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
@@ -267,7 +267,7 @@ class Gem::Package
tar.add_file_simple file, stat.mode, stat.size do |dst_io|
File.open file, "rb" do |src_io|
- copy_stream(src_io, dst_io)
+ dst_io.write src_io.read 16384 until src_io.eof?
end
end
end
@@ -277,7 +277,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
@@ -294,6 +294,7 @@ class Gem::Package
Gem.load_yaml
+ @spec.mark_version
@spec.validate true, strict_validation unless skip_validation
setup_signer(
@@ -345,8 +346,6 @@ EOM
return @contents
end
end
- rescue Zlib::GzipFile::Error, EOFError, Gem::Package::TarInvalidError => e
- raise Gem::Package::FormatError.new e.message, @gem
end
##
@@ -355,21 +354,18 @@ EOM
def digest(entry) # :nodoc:
algorithms = if @checksums
- @checksums.to_h {|algorithm, _| [algorithm, Gem::Security.create_digest(algorithm)] }
- elsif Gem::Security::DIGEST_NAME
- { Gem::Security::DIGEST_NAME => Gem::Security.create_digest(Gem::Security::DIGEST_NAME) }
+ @checksums.keys
+ else
+ [Gem::Security::DIGEST_NAME].compact
end
- return @digests if algorithms.nil? || algorithms.empty?
+ algorithms.each do |algorithm|
+ digester = Gem::Security.create_digest(algorithm)
- buf = String.new(capacity: 16_384, encoding: Encoding::BINARY)
- until entry.eof?
- entry.readpartial(16_384, buf)
- algorithms.each_value {|digester| digester << buf }
- end
- entry.rewind
+ digester << entry.read(16384) until entry.eof?
+
+ entry.rewind
- algorithms.each do |algorithm, digester|
@digests[algorithm][entry.full_name] = digester
end
@@ -385,7 +381,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
@@ -395,11 +391,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
##
@@ -414,8 +408,6 @@ EOM
# extracted.
def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc:
- destination_dir = File.realpath(destination_dir)
-
directories = []
symlinks = []
@@ -438,6 +430,8 @@ EOM
FileUtils.rm_rf destination
+ mkdir_options = {}
+ mkdir_options[:mode] = dir_mode ? 0755 : (entry.header.mode if entry.directory?)
mkdir =
if entry.directory?
destination
@@ -446,13 +440,13 @@ EOM
end
unless directories.include?(mkdir)
- FileUtils.mkdir_p mkdir, mode: dir_mode ? 0o755 : (entry.header.mode if entry.directory?)
+ FileUtils.mkdir_p mkdir, **mkdir_options
directories << mkdir
end
if entry.file?
- File.open(destination, "wb") {|out| copy_stream(entry, out) }
- FileUtils.chmod file_mode(entry.header.mode) & ~File.umask, destination
+ File.open(destination, "wb") {|out| out.write entry.read }
+ FileUtils.chmod file_mode(entry.header.mode), destination
end
verbose destination
@@ -473,7 +467,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
@@ -511,6 +505,7 @@ EOM
raise Gem::Package::PathError.new(destination, destination_dir) unless
normalize_path(destination).start_with? normalize_path(destination_dir + "/")
+ destination.tap(&Gem::UNTAINT)
destination
end
@@ -526,13 +521,12 @@ EOM
# Loads a Gem::Specification from the TarEntry +entry+
def load_spec(entry) # :nodoc:
- limit = 10 * 1024 * 1024
case entry.full_name
when "metadata" then
- @spec = Gem::Specification.from_yaml limit_read(entry, "metadata", limit)
+ @spec = Gem::Specification.from_yaml entry.read
when "metadata.gz" then
Zlib::GzipReader.wrap(entry, external_encoding: Encoding::UTF_8) do |gzio|
- @spec = Gem::Specification.from_yaml limit_read(gzio, "metadata.gz", limit)
+ @spec = Gem::Specification.from_yaml gzio.read
end
end
end
@@ -556,7 +550,7 @@ EOM
@checksums = gem.seek "checksums.yaml.gz" do |entry|
Zlib::GzipReader.wrap entry do |gz_io|
- Gem::SafeYAML.safe_load limit_read(gz_io, "checksums.yaml.gz", 10 * 1024 * 1024)
+ Gem::SafeYAML.safe_load gz_io.read
end
end
end
@@ -577,10 +571,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
@@ -622,7 +616,8 @@ EOM
verify_checksums @digests, @checksums
- @security_policy&.verify_signatures @spec, @digests, @signatures
+ @security_policy.verify_signatures @spec, @digests, @signatures if
+ @security_policy
true
rescue Gem::Security::Exception
@@ -631,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
@@ -663,7 +658,7 @@ EOM
case file_name
when /\.sig$/ then
- @signatures[$`] = limit_read(entry, file_name, 1024 * 1024) if @security_policy
+ @signatures[$`] = entry.read if @security_policy
return
else
digest entry
@@ -675,7 +670,7 @@ EOM
when "data.tar.gz" then
verify_gz entry
end
- rescue StandardError
+ rescue
warn "Exception while verifying #{@gem.path}"
raise
end
@@ -694,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
@@ -707,28 +702,11 @@ EOM
def verify_gz(entry) # :nodoc:
Zlib::GzipReader.wrap entry do |gzio|
- # TODO: read into a buffer once zlib supports it
- 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)
end
-
- if RUBY_ENGINE == "truffleruby"
- def copy_stream(src, dst) # :nodoc:
- dst.write src.read
- end
- else
- def copy_stream(src, dst) # :nodoc:
- IO.copy_stream(src, dst)
- end
- end
-
- def limit_read(io, name, limit)
- bytes = io.read(limit + 1)
- raise Gem::Package::FormatError, "#{name} is too big (over #{limit} bytes)" if bytes.size > limit
- bytes
- end
end
require_relative "package/digest_io"
diff --git a/lib/rubygems/package/digest_io.rb b/lib/rubygems/package/digest_io.rb
index f04ab97462..4736f76d93 100644
--- a/lib/rubygems/package/digest_io.rb
+++ b/lib/rubygems/package/digest_io.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# IO wrapper that creates digests of contents written to the IO it wraps.
@@ -36,7 +35,7 @@ class Gem::Package::DigestIO
yield digest_io
- digests
+ return digests
end
##
diff --git a/lib/rubygems/package/file_source.rb b/lib/rubygems/package/file_source.rb
index d9717e0f2a..14c7a9f6d2 100644
--- a/lib/rubygems/package/file_source.rb
+++ b/lib/rubygems/package/file_source.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The primary source of gems is a file on disk, including all usages
# internal to rubygems.
diff --git a/lib/rubygems/package/io_source.rb b/lib/rubygems/package/io_source.rb
index 227835dfce..03d7714524 100644
--- a/lib/rubygems/package/io_source.rb
+++ b/lib/rubygems/package/io_source.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Supports reading and writing gems from/to a generic IO object. This is
# useful for other applications built on top of rubygems, such as
diff --git a/lib/rubygems/package/old.rb b/lib/rubygems/package/old.rb
index 1a13ac3e29..09a02d3ecd 100644
--- a/lib/rubygems/package/old.rb
+++ b/lib/rubygems/package/old.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -70,7 +69,7 @@ class Gem::Package::Old < Gem::Package
file_data << line
end
- file_data = file_data.strip.unpack1("m")
+ file_data = file_data.strip.unpack("m")[0]
file_data = Zlib::Inflate.inflate file_data
raise Gem::Package::FormatError, "#{full_name} in #{@gem} is corrupt" if
@@ -78,7 +77,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/source.rb b/lib/rubygems/package/source.rb
index 8c44f8c305..69701e55e9 100644
--- a/lib/rubygems/package/source.rb
+++ b/lib/rubygems/package/source.rb
@@ -1,4 +1,3 @@
# frozen_string_literal: true
-
class Gem::Package::Source # :nodoc:
end
diff --git a/lib/rubygems/package/tar_header.rb b/lib/rubygems/package/tar_header.rb
index dd5e835a1e..590a2f0315 100644
--- a/lib/rubygems/package/tar_header.rb
+++ b/lib/rubygems/package/tar_header.rb
@@ -1,11 +1,8 @@
# 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
+#++
##
#--
@@ -95,40 +92,39 @@ class Gem::Package::TarHeader
attr_reader(*FIELDS)
- EMPTY_HEADER = ("\0" * 512).b.freeze # :nodoc:
+ EMPTY_HEADER = ("\0" * 512).freeze # :nodoc:
##
# Creates a tar header from IO +stream+
def self.from(stream)
header = stream.read 512
- return EMPTY if header == EMPTY_HEADER
+ empty = (EMPTY_HEADER == header)
fields = header.unpack UNPACK_FORMAT
- new name: fields.shift,
- mode: strict_oct(fields.shift),
- uid: oct_or_256based(fields.shift),
- gid: oct_or_256based(fields.shift),
- size: strict_oct(fields.shift),
- mtime: strict_oct(fields.shift),
- checksum: strict_oct(fields.shift),
- typeflag: fields.shift,
- linkname: fields.shift,
- magic: fields.shift,
- version: strict_oct(fields.shift),
- uname: fields.shift,
- gname: fields.shift,
- devmajor: strict_oct(fields.shift),
- devminor: strict_oct(fields.shift),
- prefix: fields.shift,
-
- empty: false
+ new :name => fields.shift,
+ :mode => strict_oct(fields.shift),
+ :uid => oct_or_256based(fields.shift),
+ :gid => oct_or_256based(fields.shift),
+ :size => strict_oct(fields.shift),
+ :mtime => strict_oct(fields.shift),
+ :checksum => strict_oct(fields.shift),
+ :typeflag => fields.shift,
+ :linkname => fields.shift,
+ :magic => fields.shift,
+ :version => strict_oct(fields.shift),
+ :uname => fields.shift,
+ :gname => fields.shift,
+ :devmajor => strict_oct(fields.shift),
+ :devminor => strict_oct(fields.shift),
+ :prefix => fields.shift,
+
+ :empty => empty
end
def self.strict_oct(str)
- str.strip!
- return str.oct if /\A[0-7]*\z/.match?(str)
+ return str.strip.oct if str.strip =~ /\A[0-7]*\z/
raise ArgumentError, "#{str.inspect} is not an octal string"
end
@@ -138,8 +134,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.unpack1("@4N") if /\A[\x80\xff]/n.match?(str)
+ return str.unpack("N2").last if str =~ /\A[\x80\xff]/n
strict_oct(str)
end
@@ -151,43 +146,25 @@ class Gem::Package::TarHeader
raise ArgumentError, ":name, :size, :prefix and :mode required"
end
- @checksum = vals[:checksum] || ""
- @devmajor = vals[:devmajor] || 0
- @devminor = vals[:devminor] || 0
- @gid = vals[:gid] || 0
- @gname = vals[:gname] || "wheel"
- @linkname = vals[:linkname]
- @magic = vals[:magic] || "ustar"
- @mode = vals[:mode]
- @mtime = vals[:mtime] || 0
- @name = vals[:name]
- @prefix = vals[:prefix]
- @size = vals[:size]
- @typeflag = vals[:typeflag]
- @typeflag = "0" if @typeflag.nil? || @typeflag.empty?
- @uid = vals[:uid] || 0
- @uname = vals[:uname] || "wheel"
- @version = vals[:version] || "00"
+ vals[:uid] ||= 0
+ vals[:gid] ||= 0
+ vals[:mtime] ||= 0
+ vals[:checksum] ||= ""
+ vals[:typeflag] = "0" if vals[:typeflag].nil? || vals[:typeflag].empty?
+ vals[:magic] ||= "ustar"
+ vals[:version] ||= "00"
+ vals[:uname] ||= "wheel"
+ vals[:gname] ||= "wheel"
+ vals[:devmajor] ||= 0
+ vals[:devminor] ||= 0
+
+ FIELDS.each do |name|
+ instance_variable_set "@#{name}", vals[name]
+ end
@empty = vals[:empty]
end
- EMPTY = new({ # :nodoc:
- checksum: 0,
- gname: "",
- linkname: "",
- magic: "",
- mode: 0,
- name: "",
- prefix: "",
- size: 0,
- uname: "",
- version: 0,
-
- empty: true,
- }).freeze
- private_constant :EMPTY
-
##
# Is the tar entry empty?
@@ -231,7 +208,7 @@ class Gem::Package::TarHeader
private
def calculate_checksum(header)
- header.sum(0)
+ header.unpack("C*").inject {|a, b| a + b }
end
def header(checksum = @checksum)
@@ -257,10 +234,10 @@ class Gem::Package::TarHeader
header = header.pack PACK_FORMAT
- header.ljust 512, "\0"
+ header << ("\0" * ((512 - header.size) % 512))
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..cdc3fdc015 100644
--- a/lib/rubygems/package/tar_reader.rb
+++ b/lib/rubygems/package/tar_reader.rb
@@ -1,11 +1,8 @@
# 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 +11,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)
@@ -51,23 +53,44 @@ class Gem::Package::TarReader
def each
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
+ use_seek = @io.respond_to?(:seek)
+ until @io.eof? do
+ header = Gem::Package::TarHeader.from @io
return if header.empty?
+
entry = Gem::Package::TarReader::Entry.new header, @io
+ size = entry.header.size
+
yield entry
+
+ skip = (512 - (size % 512)) % 512
+ pending = size - entry.bytes_read
+
+ if use_seek
+ begin
+ # avoid reading if the @io supports seeking
+ @io.seek pending, IO::SEEK_CUR
+ pending = 0
+ rescue Errno::EINVAL
+ end
+ end
+
+ # if seeking isn't supported or failed
+ while pending > 0 do
+ bytes_read = @io.read([pending, 4096].min).size
+ raise UnexpectedEOF if @io.eof?
+ pending -= bytes_read
+ end
+
+ @io.read skip # discard trailing zeros
+
+ # make sure nobody can use #read, #getc or #rewind anymore
entry.close
end
end
- alias_method :each_entry, :each
+ alias each_entry each
##
# NOTE: Do not call #rewind during #each
@@ -92,7 +115,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..8634381c18 100644
--- a/lib/rubygems/package/tar_reader/entry.rb
+++ b/lib/rubygems/package/tar_reader/entry.rb
@@ -1,31 +1,14 @@
# 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
class Gem::Package::TarReader::Entry
##
- # Creates a new tar entry for +header+ that will be read from +io+
- # If a block is given, the entry is yielded and then closed.
-
- def self.open(header, io, &block)
- entry = new header, io
- return entry unless block_given?
- begin
- yield entry
- ensure
- entry.close
- end
- end
-
- ##
# Header for this tar entry
attr_reader :header
@@ -38,7 +21,6 @@ class Gem::Package::TarReader::Entry
@header = header
@io = io
@orig_pos = @io.pos
- @end_pos = @orig_pos + @header.size
@read = 0
end
@@ -57,14 +39,7 @@ class Gem::Package::TarReader::Entry
# Closes the tar entry
def close
- return if closed?
- # Seek to the end of the entry if it wasn't fully read
- seek(0, IO::SEEK_END)
- # discard trailing zeros
- skip = (512 - (@header.size % 512)) % 512
- @io.read(skip)
@closed = true
- nil
end
##
@@ -102,7 +77,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
@@ -140,43 +117,36 @@ class Gem::Package::TarReader::Entry
bytes_read
end
- ##
- # Seek to the position in the tar entry
-
- def pos=(new_pos)
- seek(new_pos, IO::SEEK_SET)
- 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
+
+ return nil if @read >= @header.size
- max_read = [maxlen, @header.size - @read].compact.min
+ len ||= @header.size - @read
+ 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
+ raise EOFError if @read >= @header.size
+
+ maxlen ||= @header.size - @read
max_read = [maxlen, @header.size - @read].min
@io.readpartial(max_read, outbuf)
@@ -186,63 +156,12 @@ class Gem::Package::TarReader::Entry
end
##
- # Seeks to +offset+ bytes into the tar file entry
- # +whence+ can be IO::SEEK_SET, IO::SEEK_CUR, or IO::SEEK_END
-
- def seek(offset, whence = IO::SEEK_SET)
- check_closed
-
- new_pos =
- case whence
- when IO::SEEK_SET then @orig_pos + offset
- when IO::SEEK_CUR then @io.pos + offset
- when IO::SEEK_END then @end_pos + offset
- else
- raise ArgumentError, "invalid whence"
- end
-
- if new_pos < @orig_pos
- new_pos = @orig_pos
- elsif new_pos > @end_pos
- new_pos = @end_pos
- end
-
- pending = new_pos - @io.pos
-
- return 0 if pending == 0
-
- if @io.respond_to?(:seek)
- begin
- # avoid reading if the @io supports seeking
- @io.seek new_pos, IO::SEEK_SET
- pending = 0
- rescue Errno::EINVAL
- end
- end
-
- # if seeking isn't supported or failed
- # negative seek requires that we rewind and read
- if pending < 0
- @io.rewind
- pending = new_pos
- end
-
- while pending > 0 do
- size_read = @io.read([pending, 4096].min)&.size
- raise(EOFError, "end of file reached") if size_read.nil?
- pending -= size_read
- end
-
- @read = @io.pos - @orig_pos
-
- 0
- end
-
- ##
# Rewinds to the beginning of the tar file entry
def rewind
check_closed
- seek(0, IO::SEEK_SET)
+
+ @io.pos = @orig_pos
+ @read = 0
end
end
diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb
index b24bdb63e7..db5242c5e4 100644
--- a/lib/rubygems/package/tar_writer.rb
+++ b/lib/rubygems/package/tar_writer.rb
@@ -1,11 +1,8 @@
# 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
@@ -116,9 +113,9 @@ class Gem::Package::TarWriter
final_pos = @io.pos
@io.pos = init_pos
- header = Gem::Package::TarHeader.new name: name, mode: mode,
- size: size, prefix: prefix,
- mtime: Gem.source_date_epoch
+ header = Gem::Package::TarHeader.new :name => name, :mode => mode,
+ :size => size, :prefix => prefix,
+ :mtime => Gem.source_date_epoch
@io.write header
@io.pos = final_pos
@@ -192,7 +189,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
@@ -209,9 +206,9 @@ class Gem::Package::TarWriter
name, prefix = split_name name
- header = Gem::Package::TarHeader.new(name: name, mode: mode,
- size: size, prefix: prefix,
- mtime: Gem.source_date_epoch).to_s
+ header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
+ :size => size, :prefix => prefix,
+ :mtime => Gem.source_date_epoch).to_s
@io.write header
os = BoundedStream.new @io, size
@@ -235,11 +232,11 @@ class Gem::Package::TarWriter
name, prefix = split_name name
- header = Gem::Package::TarHeader.new(name: name, mode: mode,
- size: 0, typeflag: "2",
- linkname: target,
- prefix: prefix,
- mtime: Gem.source_date_epoch).to_s
+ header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
+ :size => 0, :typeflag => "2",
+ :linkname => target,
+ :prefix => prefix,
+ :mtime => Gem.source_date_epoch).to_s
@io.write header
@@ -289,10 +286,10 @@ class Gem::Package::TarWriter
name, prefix = split_name(name)
- header = Gem::Package::TarHeader.new name: name, mode: mode,
- typeflag: "5", size: 0,
- prefix: prefix,
- mtime: Gem.source_date_epoch
+ header = Gem::Package::TarHeader.new :name => name, :mode => mode,
+ :typeflag => "5", :size => 0,
+ :prefix => prefix,
+ :mtime => Gem.source_date_epoch
@io.write header
@@ -326,6 +323,6 @@ class Gem::Package::TarWriter
end
end
- [name, prefix]
+ return name, prefix
end
end
diff --git a/lib/rubygems/package_task.rb b/lib/rubygems/package_task.rb
index d26411684d..8432bc5806 100644
--- a/lib/rubygems/package_task.rb
+++ b/lib/rubygems/package_task.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
# Copyright (c) 2003, 2004 Jim Weirich, 2009 Eric Hodel
#
# Permission is hereby granted, free of charge, to any person obtaining
@@ -97,13 +96,13 @@ class Gem::PackageTask < Rake::PackageTask
gem_path = File.join package_dir, gem_file
gem_dir = File.join package_dir, gem_spec.full_name
- task package: [:gem]
+ task :package => [:gem]
directory package_dir
directory gem_dir
desc "Build the gem file #{gem_file}"
- task gem: [gem_path]
+ task :gem => [gem_path]
trace = Rake.application.options.trace
Gem.configuration.verbose = trace
diff --git a/lib/rubygems/path_support.rb b/lib/rubygems/path_support.rb
index 13091e29ba..d601e653c9 100644
--- a/lib/rubygems/path_support.rb
+++ b/lib/rubygems/path_support.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
#
# Gem::PathSupport facilitates the GEM_HOME and GEM_PATH environment settings
@@ -24,22 +23,23 @@ class Gem::PathSupport
# hashtable, or defaults to ENV, the system environment.
#
def initialize(env)
- @home = normalize_home_dir(env["GEM_HOME"] || Gem.default_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
+
+ @spec_cache_dir = @spec_cache_dir.dup.tap(&Gem::UNTAINT)
end
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).
@@ -52,7 +52,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 dac3b1269f..128871f2bf 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "deprecate"
##
@@ -13,22 +12,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|
@@ -43,20 +35,10 @@ class Gem::Platform
match_gem?(spec.platform, spec.name)
end
- if RUBY_ENGINE == "truffleruby"
- def self.match_gem?(platform, gem_name)
- raise "Not a string: #{gem_name.inspect}" unless String === gem_name
-
- if REUSE_AS_BINARY_ON_TRUFFLERUBY.include?(gem_name)
- match_platforms?(platform, [Gem::Platform::RUBY, Gem::Platform.local])
- else
- match_platforms?(platform, Gem.platforms)
- end
- end
- else
- def self.match_gem?(platform, gem_name)
- match_platforms?(platform, Gem.platforms)
- end
+ def self.match_gem?(platform, gem_name)
+ # 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
def self.sort_priority(platform)
@@ -89,7 +71,7 @@ class Gem::Platform
when String then
arch = arch.split "-"
- if arch.length > 2 && !arch.last.match?(/\d+(\.\d+)?$/) # reassemble x86-linux-{libc}
+ if arch.length > 2 && arch.last !~ /\d+(\.\d+)?$/ # reassemble x86-linux-{libc}
extra = arch.pop
arch.last << "-#{extra}"
end
@@ -97,47 +79,42 @@ 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.match?(/^\d+(\.\d+)?$/) # for command-line
+ if arch.length == 2 && arch.last =~ /^\d+(\.\d+)?$/ # for command-line
@os, @version = arch
return
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]
- when /wasi/ then ["wasi", nil]
- # 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
@@ -164,7 +141,7 @@ class Gem::Platform
self.class === other && to_a == other.to_a
end
- alias_method :eql?, :==
+ alias :eql? :==
def hash # :nodoc:
to_a.hash
@@ -176,7 +153,7 @@ class Gem::Platform
# they have the same version, or either one has no version
#
# Additionally, the platform will match if the local CPU is 'arm' and the
- # other CPU starts with "armv" (for generic 32-bit ARM family support).
+ # other CPU starts with "arm" (for generic ARM family support).
#
# Of note, this method is not commutative. Indeed the OS 'linux' has a
# special case: the version is the libc name, yet while "no version" stands
@@ -197,7 +174,7 @@ class Gem::Platform
# cpu
([nil,"universal"].include?(@cpu) || [nil, "universal"].include?(other.cpu) || @cpu == other.cpu ||
- (@cpu == "arm" && other.cpu.start_with?("armv"))) &&
+ (@cpu == "arm" && other.cpu.start_with?("arm"))) &&
# os
@os == other.os &&
@@ -232,18 +209,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
@@ -258,11 +235,11 @@ class Gem::Platform
# A pure-Ruby gem that may use Gem::Specification#extensions to build
# binary files.
- RUBY = "ruby"
+ RUBY = "ruby".freeze
##
# A platform-specific gem that is built for the packaging Ruby's platform.
# This will be replaced with Gem::Platform::local.
- CURRENT = "current"
+ CURRENT = "current".freeze
end
diff --git a/lib/rubygems/psych_tree.rb b/lib/rubygems/psych_tree.rb
index 2d478c94d9..b90f9f7d1d 100644
--- a/lib/rubygems/psych_tree.rb
+++ b/lib/rubygems/psych_tree.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
module Gem
if defined? ::Psych::Visitors
class NoAliasYAMLTree < Psych::Visitors::YAMLTree
diff --git a/lib/rubygems/query_utils.rb b/lib/rubygems/query_utils.rb
index ea05969422..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?
@@ -132,7 +133,7 @@ module Gem::QueryUtils
version_matches = show_prereleases? || !s.version.prerelease?
name_matches && version_matches
- end.uniq(&:full_name)
+ end
spec_tuples = specs.map do |spec|
[spec.name_tuple, spec]
@@ -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/rdoc.rb b/lib/rubygems/rdoc.rb
index 907dcd9431..769ec61d1e 100644
--- a/lib/rubygems/rdoc.rb
+++ b/lib/rubygems/rdoc.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../rubygems"
begin
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index 4b5c74e0ea..0ac6eaa130 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../rubygems"
require_relative "request"
require_relative "request/connection_pools"
@@ -53,7 +52,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
@@ -74,8 +73,9 @@ class Gem::RemoteFetcher
def initialize(proxy=nil, dns=nil, headers={})
require_relative "core_ext/tcpsocket_init" if Gem.configuration.ipv4_fallback_enabled
- require_relative "vendored_net_http"
- require_relative "vendor/uri/lib/uri"
+ require "net/http"
+ require "stringio"
+ require "uri"
Socket.do_not_reverse_lookup = true
@@ -114,7 +114,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"
@@ -124,18 +124,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
- # Gem::URI.parse gets confused by MS Windows paths with forward slashes.
- scheme = nil if /^[a-z]$/i.match?(scheme)
+ # URI.parse gets confused by MS Windows paths with forward slashes.
+ 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
@@ -147,7 +143,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
@@ -157,7 +153,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
@@ -173,7 +169,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}"
@@ -209,17 +205,17 @@ class Gem::RemoteFetcher
# HTTP Fetcher. Dispatched by +fetch_path+. Use it instead.
def fetch_http(uri, last_modified = nil, head = false, depth = 0)
- fetch_type = head ? Gem::Net::HTTP::Head : Gem::Net::HTTP::Get
+ fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get
response = request uri, fetch_type, last_modified do |req|
headers.each {|k,v| req.add_field(k,v) }
end
case response
- when Gem::Net::HTTPOK, Gem::Net::HTTPNotModified then
+ when Net::HTTPOK, Net::HTTPNotModified then
response.uri = uri
head ? response : response.body
- when Gem::Net::HTTPMovedPermanently, Gem::Net::HTTPFound, Gem::Net::HTTPSeeOther,
- Gem::Net::HTTPTemporaryRedirect then
+ when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther,
+ Net::HTTPTemporaryRedirect then
raise FetchError.new("too many redirects", uri) if depth > 10
unless location = response["Location"]
@@ -237,7 +233,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.
@@ -260,7 +256,7 @@ class Gem::RemoteFetcher
end
data
- rescue Gem::Timeout::Error, IOError, SocketError, SystemCallError,
+ rescue Timeout::Error, IOError, SocketError, SystemCallError,
*(OpenSSL::SSL::SSLError if Gem::HAVE_OPENSSL) => e
raise FetchError.new("#{e.class}: #{e}", uri)
end
@@ -284,11 +280,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)
@@ -304,8 +296,8 @@ class Gem::RemoteFetcher
end
##
- # Performs a Gem::Net::HTTP request of type +request_class+ on +uri+ returning
- # a Gem::Net::HTTP response object. request maintains a table of persistent
+ # Performs a Net::HTTP request of type +request_class+ on +uri+ returning
+ # a Net::HTTP response object. request maintains a table of persistent
# connections to reduce connect overhead.
def request(uri, request_class, last_modified = nil)
@@ -320,11 +312,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 9116785231..c3ea46e0eb 100644
--- a/lib/rubygems/request.rb
+++ b/lib/rubygems/request.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-
-require_relative "vendored_net_http"
+require "net/http"
require_relative "user_interaction"
class Gem::Request
@@ -18,11 +17,11 @@ class Gem::Request
end
def self.proxy_uri(proxy) # :nodoc:
- require_relative "vendor/uri/lib/uri"
+ require "uri"
case proxy
when :no_proxy then nil
- when Gem::URI::HTTP then proxy
- else Gem::URI.parse(proxy)
+ when URI::HTTP then proxy
+ else URI.parse(proxy)
end
end
@@ -30,19 +29,14 @@ class Gem::Request
@uri = uri
@request_class = request_class
@last_modified = last_modified
- @requests = Hash.new(0).compare_by_identity
+ @requests = Hash.new 0
@user_agent = user_agent
@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 +159,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 = Gem::URI(Gem::UriFormatter.new(env_proxy).normalize)
+ 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
@@ -196,7 +191,7 @@ class Gem::Request
bad_response = false
begin
- @requests[connection] += 1
+ @requests[connection.object_id] += 1
verbose "#{request.method} #{Gem::Uri.redact(@uri)}"
@@ -205,7 +200,7 @@ class Gem::Request
if request.response_body_permitted? && file_name =~ /\.gem$/
reporter = ui.download_reporter
response = connection.request(request) do |incomplete_response|
- if Gem::Net::HTTPOK === incomplete_response
+ if Net::HTTPOK === incomplete_response
reporter.fetch(file_name, incomplete_response.content_length)
downloaded = 0
data = String.new
@@ -228,7 +223,8 @@ class Gem::Request
end
verbose "#{response.code} #{response.message}"
- rescue Gem::Net::HTTPBadResponse
+
+ rescue Net::HTTPBadResponse
verbose "bad response"
reset connection
@@ -237,17 +233,17 @@ class Gem::Request
bad_response = true
retry
- rescue Gem::Net::HTTPFatalError
+ rescue Net::HTTPFatalError
verbose "fatal error"
raise Gem::RemoteFetcher::FetchError.new("fatal error", @uri)
- # HACK: work around EOFError bug in Gem::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, Gem::Timeout::Error,
+ rescue EOFError, Timeout::Error,
Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE
- requests = @requests[connection]
+ requests = @requests[connection.object_id]
verbose "connection reset after #{requests} requests, retrying"
raise Gem::RemoteFetcher::FetchError.new("too many connection resets", @uri) if retried
@@ -267,7 +263,7 @@ class Gem::Request
# Resets HTTP connection +connection+.
def reset(connection)
- @requests.delete connection
+ @requests.delete connection.object_id
connection.finish
connection.start
@@ -282,7 +278,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 6c1b04ab65..44280489fb 100644
--- a/lib/rubygems/request/connection_pools.rb
+++ b/lib/rubygems/request/connection_pools.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Gem::Request::ConnectionPools # :nodoc:
- @client = Gem::Net::HTTP
+ @client = Net::HTTP
class << self
attr_accessor :client
@@ -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/http_pool.rb b/lib/rubygems/request/http_pool.rb
index 52543de41f..7b309eedd3 100644
--- a/lib/rubygems/request/http_pool.rb
+++ b/lib/rubygems/request/http_pool.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A connection "pool" that only manages one connection for now. Provides
# thread safe `checkout` and `checkin` methods. The pool consists of one
diff --git a/lib/rubygems/request/https_pool.rb b/lib/rubygems/request/https_pool.rb
index cb1d4b59b6..50f42d9e0d 100644
--- a/lib/rubygems/request/https_pool.rb
+++ b/lib/rubygems/request/https_pool.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
class Gem::Request::HTTPSPool < Gem::Request::HTTPPool # :nodoc:
private
diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb
index 875df7e019..64701a8214 100644
--- a/lib/rubygems/request_set.rb
+++ b/lib/rubygems/request_set.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-
-require_relative "vendored_tsort"
+require_relative "tsort"
##
# A RequestSet groups a request to activate a set of dependencies.
@@ -108,7 +107,7 @@ class Gem::RequestSet
@requests = []
@sets = []
@soft_missing = false
- @sorted_requests = nil
+ @sorted = nil
@specs = nil
@vendor_set = nil
@source_set = nil
@@ -160,7 +159,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 +254,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 }
@@ -324,7 +322,7 @@ class Gem::RequestSet
@git_set.root_dir = @install_dir
- lock_file = "#{File.expand_path(path)}.lock"
+ lock_file = "#{File.expand_path(path)}.lock".dup.tap(&Gem::UNTAINT)
begin
tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file lock_file
parser = tokenizer.make_parser self, []
@@ -376,7 +374,7 @@ class Gem::RequestSet
q.text "sets:"
q.breakable
- q.pp @sets.map(&:class)
+ q.pp @sets.map {|set| set.class }
end
end
@@ -426,11 +424,11 @@ class Gem::RequestSet
end
def sorted_requests
- @sorted_requests ||= strongly_connected_components.flatten
+ @sorted ||= strongly_connected_components.flatten
end
def specs
- @specs ||= @requests.map(&:full_spec)
+ @specs ||= @requests.map {|r| r.full_spec }
end
def specs_in(dir)
@@ -448,7 +446,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 4347d22ccb..ad6e45005b 100644
--- a/lib/rubygems/request_set/gem_dependency_api.rb
+++ b/lib/rubygems/request_set/gem_dependency_api.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A semi-compatible DSL for the Bundler Gemfile and Isolate gem dependencies
# files.
@@ -33,22 +32,22 @@
class Gem::RequestSet::GemDependencyAPI
ENGINE_MAP = { # :nodoc:
- jruby: %w[jruby],
- jruby_18: %w[jruby],
- jruby_19: %w[jruby],
- maglev: %w[maglev],
- mri: %w[ruby],
- mri_18: %w[ruby],
- mri_19: %w[ruby],
- mri_20: %w[ruby],
- mri_21: %w[ruby],
- rbx: %w[rbx],
- truffleruby: %w[truffleruby],
- ruby: %w[ruby rbx maglev truffleruby],
- ruby_18: %w[ruby rbx maglev truffleruby],
- ruby_19: %w[ruby rbx maglev truffleruby],
- ruby_20: %w[ruby rbx maglev truffleruby],
- ruby_21: %w[ruby rbx maglev truffleruby],
+ :jruby => %w[jruby],
+ :jruby_18 => %w[jruby],
+ :jruby_19 => %w[jruby],
+ :maglev => %w[maglev],
+ :mri => %w[ruby],
+ :mri_18 => %w[ruby],
+ :mri_19 => %w[ruby],
+ :mri_20 => %w[ruby],
+ :mri_21 => %w[ruby],
+ :rbx => %w[rbx],
+ :truffleruby => %w[truffleruby],
+ :ruby => %w[ruby rbx maglev truffleruby],
+ :ruby_18 => %w[ruby rbx maglev truffleruby],
+ :ruby_19 => %w[ruby rbx maglev truffleruby],
+ :ruby_20 => %w[ruby rbx maglev truffleruby],
+ :ruby_21 => %w[ruby rbx maglev truffleruby],
}.freeze
mswin = Gem::Platform.new "x86-mswin32"
@@ -57,39 +56,39 @@ class Gem::RequestSet::GemDependencyAPI
x64_mingw = Gem::Platform.new "x64-mingw32"
PLATFORM_MAP = { # :nodoc:
- jruby: Gem::Platform::RUBY,
- jruby_18: Gem::Platform::RUBY,
- jruby_19: Gem::Platform::RUBY,
- maglev: Gem::Platform::RUBY,
- mingw: x86_mingw,
- mingw_18: x86_mingw,
- mingw_19: x86_mingw,
- mingw_20: x86_mingw,
- mingw_21: x86_mingw,
- mri: Gem::Platform::RUBY,
- mri_18: Gem::Platform::RUBY,
- mri_19: Gem::Platform::RUBY,
- mri_20: Gem::Platform::RUBY,
- mri_21: Gem::Platform::RUBY,
- mswin: mswin,
- mswin_18: mswin,
- mswin_19: mswin,
- mswin_20: mswin,
- mswin_21: mswin,
- mswin64: mswin64,
- mswin64_19: mswin64,
- mswin64_20: mswin64,
- mswin64_21: mswin64,
- rbx: Gem::Platform::RUBY,
- ruby: Gem::Platform::RUBY,
- ruby_18: Gem::Platform::RUBY,
- ruby_19: Gem::Platform::RUBY,
- ruby_20: Gem::Platform::RUBY,
- ruby_21: Gem::Platform::RUBY,
- truffleruby: Gem::Platform::RUBY,
- x64_mingw: x64_mingw,
- x64_mingw_20: x64_mingw,
- x64_mingw_21: x64_mingw,
+ :jruby => Gem::Platform::RUBY,
+ :jruby_18 => Gem::Platform::RUBY,
+ :jruby_19 => Gem::Platform::RUBY,
+ :maglev => Gem::Platform::RUBY,
+ :mingw => x86_mingw,
+ :mingw_18 => x86_mingw,
+ :mingw_19 => x86_mingw,
+ :mingw_20 => x86_mingw,
+ :mingw_21 => x86_mingw,
+ :mri => Gem::Platform::RUBY,
+ :mri_18 => Gem::Platform::RUBY,
+ :mri_19 => Gem::Platform::RUBY,
+ :mri_20 => Gem::Platform::RUBY,
+ :mri_21 => Gem::Platform::RUBY,
+ :mswin => mswin,
+ :mswin_18 => mswin,
+ :mswin_19 => mswin,
+ :mswin_20 => mswin,
+ :mswin_21 => mswin,
+ :mswin64 => mswin64,
+ :mswin64_19 => mswin64,
+ :mswin64_20 => mswin64,
+ :mswin64_21 => mswin64,
+ :rbx => Gem::Platform::RUBY,
+ :ruby => Gem::Platform::RUBY,
+ :ruby_18 => Gem::Platform::RUBY,
+ :ruby_19 => Gem::Platform::RUBY,
+ :ruby_20 => Gem::Platform::RUBY,
+ :ruby_21 => Gem::Platform::RUBY,
+ :truffleruby => Gem::Platform::RUBY,
+ :x64_mingw => x64_mingw,
+ :x64_mingw_20 => x64_mingw,
+ :x64_mingw_21 => x64_mingw,
}.freeze
gt_eq_0 = Gem::Requirement.new ">= 0"
@@ -99,70 +98,70 @@ class Gem::RequestSet::GemDependencyAPI
tilde_gt_2_1_0 = Gem::Requirement.new "~> 2.1.0"
VERSION_MAP = { # :nodoc:
- jruby: gt_eq_0,
- jruby_18: tilde_gt_1_8_0,
- jruby_19: tilde_gt_1_9_0,
- maglev: gt_eq_0,
- mingw: gt_eq_0,
- mingw_18: tilde_gt_1_8_0,
- mingw_19: tilde_gt_1_9_0,
- mingw_20: tilde_gt_2_0_0,
- mingw_21: tilde_gt_2_1_0,
- mri: gt_eq_0,
- mri_18: tilde_gt_1_8_0,
- mri_19: tilde_gt_1_9_0,
- mri_20: tilde_gt_2_0_0,
- mri_21: tilde_gt_2_1_0,
- mswin: gt_eq_0,
- mswin_18: tilde_gt_1_8_0,
- mswin_19: tilde_gt_1_9_0,
- mswin_20: tilde_gt_2_0_0,
- mswin_21: tilde_gt_2_1_0,
- mswin64: gt_eq_0,
- mswin64_19: tilde_gt_1_9_0,
- mswin64_20: tilde_gt_2_0_0,
- mswin64_21: tilde_gt_2_1_0,
- rbx: gt_eq_0,
- ruby: gt_eq_0,
- ruby_18: tilde_gt_1_8_0,
- ruby_19: tilde_gt_1_9_0,
- ruby_20: tilde_gt_2_0_0,
- ruby_21: tilde_gt_2_1_0,
- truffleruby: gt_eq_0,
- x64_mingw: gt_eq_0,
- x64_mingw_20: tilde_gt_2_0_0,
- x64_mingw_21: tilde_gt_2_1_0,
+ :jruby => gt_eq_0,
+ :jruby_18 => tilde_gt_1_8_0,
+ :jruby_19 => tilde_gt_1_9_0,
+ :maglev => gt_eq_0,
+ :mingw => gt_eq_0,
+ :mingw_18 => tilde_gt_1_8_0,
+ :mingw_19 => tilde_gt_1_9_0,
+ :mingw_20 => tilde_gt_2_0_0,
+ :mingw_21 => tilde_gt_2_1_0,
+ :mri => gt_eq_0,
+ :mri_18 => tilde_gt_1_8_0,
+ :mri_19 => tilde_gt_1_9_0,
+ :mri_20 => tilde_gt_2_0_0,
+ :mri_21 => tilde_gt_2_1_0,
+ :mswin => gt_eq_0,
+ :mswin_18 => tilde_gt_1_8_0,
+ :mswin_19 => tilde_gt_1_9_0,
+ :mswin_20 => tilde_gt_2_0_0,
+ :mswin_21 => tilde_gt_2_1_0,
+ :mswin64 => gt_eq_0,
+ :mswin64_19 => tilde_gt_1_9_0,
+ :mswin64_20 => tilde_gt_2_0_0,
+ :mswin64_21 => tilde_gt_2_1_0,
+ :rbx => gt_eq_0,
+ :ruby => gt_eq_0,
+ :ruby_18 => tilde_gt_1_8_0,
+ :ruby_19 => tilde_gt_1_9_0,
+ :ruby_20 => tilde_gt_2_0_0,
+ :ruby_21 => tilde_gt_2_1_0,
+ :truffleruby => gt_eq_0,
+ :x64_mingw => gt_eq_0,
+ :x64_mingw_20 => tilde_gt_2_0_0,
+ :x64_mingw_21 => tilde_gt_2_1_0,
}.freeze
WINDOWS = { # :nodoc:
- mingw: :only,
- mingw_18: :only,
- mingw_19: :only,
- mingw_20: :only,
- mingw_21: :only,
- mri: :never,
- mri_18: :never,
- mri_19: :never,
- mri_20: :never,
- mri_21: :never,
- mswin: :only,
- mswin_18: :only,
- mswin_19: :only,
- mswin_20: :only,
- mswin_21: :only,
- mswin64: :only,
- mswin64_19: :only,
- mswin64_20: :only,
- mswin64_21: :only,
- rbx: :never,
- ruby: :never,
- ruby_18: :never,
- ruby_19: :never,
- ruby_20: :never,
- ruby_21: :never,
- x64_mingw: :only,
- x64_mingw_20: :only,
- x64_mingw_21: :only,
+ :mingw => :only,
+ :mingw_18 => :only,
+ :mingw_19 => :only,
+ :mingw_20 => :only,
+ :mingw_21 => :only,
+ :mri => :never,
+ :mri_18 => :never,
+ :mri_19 => :never,
+ :mri_20 => :never,
+ :mri_21 => :never,
+ :mswin => :only,
+ :mswin_18 => :only,
+ :mswin_19 => :only,
+ :mswin_20 => :only,
+ :mswin_21 => :only,
+ :mswin64 => :only,
+ :mswin64_19 => :only,
+ :mswin64_20 => :only,
+ :mswin64_21 => :only,
+ :rbx => :never,
+ :ruby => :never,
+ :ruby_18 => :never,
+ :ruby_19 => :never,
+ :ruby_20 => :never,
+ :ruby_21 => :never,
+ :x64_mingw => :only,
+ :x64_mingw_20 => :only,
+ :x64_mingw_21 => :only,
}.freeze
##
@@ -262,7 +261,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
@@ -280,7 +279,7 @@ class Gem::RequestSet::GemDependencyAPI
# Loads the gem dependency file and returns self.
def load
- instance_eval File.read(@path), @path, 1
+ instance_eval File.read(@path).tap(&Gem::UNTAINT), @path, 1
self
end
@@ -357,7 +356,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
@@ -436,6 +435,7 @@ Gem dependencies file #{@path} requires #{name} more than once.
reference ||= ref
reference ||= branch
reference ||= tag
+ reference ||= "master"
if ref && branch
warn <<-WARNING
@@ -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 c446b3ae51..3ba202f661 100644
--- a/lib/rubygems/request_set/lockfile.rb
+++ b/lib/rubygems/request_set/lockfile.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Parses a gem.deps.rb.lock file and constructs a LockSet containing the
# dependencies found inside. If the lock file is missing no LockSet is
@@ -76,13 +75,18 @@ class Gem::RequestSet::Lockfile
@dependencies = dependencies
@gem_deps_file = File.expand_path(gem_deps_file)
@gem_deps_dir = File.dirname(@gem_deps_file)
+
+ if RUBY_VERSION < "2.7"
+ @gem_deps_file.untaint unless gem_deps_file.tainted?
+ end
+
@platforms = []
end
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}"
}
@@ -101,10 +105,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})"
@@ -133,10 +137,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
@@ -180,7 +184,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..8446f9df8e 100644
--- a/lib/rubygems/request_set/lockfile/parser.rb
+++ b/lib/rubygems/request_set/lockfile/parser.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
class Gem::RequestSet::Lockfile::Parser
###
# Parses lockfiles
@@ -48,7 +47,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 +56,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 +67,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 +110,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 +127,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 +199,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 +246,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 +281,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
@@ -332,7 +331,7 @@ class Gem::RequestSet::Lockfile::Parser
set.find_all(requirement)
end.compact.first
- specification&.version
+ specification && specification.version
end
##
diff --git a/lib/rubygems/request_set/lockfile/tokenizer.rb b/lib/rubygems/request_set/lockfile/tokenizer.rb
index 65cef3baa0..4476a041c4 100644
--- a/lib/rubygems/request_set/lockfile/tokenizer.rb
+++ b/lib/rubygems/request_set/lockfile/tokenizer.rb
@@ -1,6 +1,4 @@
-# frozen_string_literal: true
-
-# ) frozen_string_literal: true
+#) frozen_string_literal: true
require_relative "parser"
class Gem::RequestSet::Lockfile::Tokenizer
@@ -50,7 +48,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 +73,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 +87,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 10d4befc7b..64f9ac3465 100644
--- a/lib/rubygems/requirement.rb
+++ b/lib/rubygems/requirement.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "version"
##
@@ -10,11 +9,11 @@ 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 },
- "<" => lambda {|v, r| v < r },
+ ">" => lambda {|v, r| v > r },
+ "<" => lambda {|v, r| v < r },
">=" => lambda {|v, r| v >= r },
"<=" => lambda {|v, r| v <= r },
"~>" => lambda {|v, r| v >= r && v.release < r.bump },
@@ -28,7 +27,7 @@ class Gem::Requirement
##
# A regular expression that matches a requirement
- PATTERN = /\A#{PATTERN_RAW}\z/
+ PATTERN = /\A#{PATTERN_RAW}\z/.freeze
##
# The default requirement matches any non-prerelease version
@@ -120,7 +119,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 +155,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 +163,7 @@ class Gem::Requirement
"#{op} #{version}"
end.uniq
- " (#{list.join ", "})"
+ " (#{list.join ', '})"
end
##
@@ -245,8 +244,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.
@@ -284,11 +283,6 @@ class Gem::Requirement
def _tilde_requirements
@_tilde_requirements ||= _sorted_requirements.select {|r| r.first == "~>" }
end
-
- def initialize_copy(other) # :nodoc:
- @requirements = other.requirements.dup
- super
- end
end
class Gem::Version
diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb
index 115c716b6b..76d1e9d0cc 100644
--- a/lib/rubygems/resolver.rb
+++ b/lib/rubygems/resolver.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "dependency"
require_relative "exceptions"
require_relative "util/list"
@@ -11,7 +10,7 @@ require_relative "util/list"
# all the requirements.
class Gem::Resolver
- require_relative "vendored_molinillo"
+ require_relative "resolver/molinillo"
##
# If the DEBUG_RESOLVER environment variable is set then debugging mode is
@@ -38,6 +37,8 @@ class Gem::Resolver
##
# List of dependencies that could not be found in the configured sources.
+ attr_reader :missing
+
attr_reader :stats
##
@@ -47,7 +48,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 +105,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 +114,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 +144,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:
@@ -167,7 +170,7 @@ class Gem::Resolver
reqs
end
- include Gem::Molinillo::UI
+ include Molinillo::UI
def output
@output ||= debug? ? $stdout : File.open(IO::NULL, "w")
@@ -177,14 +180,15 @@ class Gem::Resolver
DEBUG_RESOLVER
end
- include Gem::Molinillo::SpecificationProvider
+ include Molinillo::SpecificationProvider
##
# Proceed with resolution! Returns an array of ActivationRequest objects.
def resolve
- Gem::Molinillo::Resolver.new(self, self).resolve(@needed.map {|d| DependencyRequest.new d, nil }).tsort.map(&:payload).compact
- rescue Gem::Molinillo::VersionConflict => e
+ 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)
ensure
@@ -208,7 +212,7 @@ class Gem::Resolver
matching_platform = select_local_platforms all
- [matching_platform, all]
+ return matching_platform, all
end
##
@@ -223,6 +227,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 +246,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 +274,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 5c722001b1..27877e0f4b 100644
--- a/lib/rubygems/resolver/activation_request.rb
+++ b/lib/rubygems/resolver/activation_request.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Specifies a Specification object that should be activated. Also contains a
# dependency that was used to introduce this activation.
@@ -59,8 +58,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 +93,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
##
@@ -106,7 +109,7 @@ class Gem::Resolver::ActivationRequest
this_spec = full_spec
Gem::Specification.any? do |s|
- s == this_spec && s.base_dir == this_spec.base_dir
+ s == this_spec
end
end
end
diff --git a/lib/rubygems/resolver/api_set.rb b/lib/rubygems/resolver/api_set.rb
index 9f6695a6a9..f2bef54a9c 100644
--- a/lib/rubygems/resolver/api_set.rb
+++ b/lib/rubygems/resolver/api_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The global rubygems pool, available via the rubygems.org API.
# Returns instances of APISpecification.
@@ -30,7 +29,7 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
def initialize(dep_uri = "https://index.rubygems.org/info/")
super()
- dep_uri = Gem::URI dep_uri unless Gem::URI === dep_uri
+ dep_uri = URI dep_uri unless URI === dep_uri
@dep_uri = dep_uri
@uri = dep_uri + ".."
@@ -76,8 +75,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)
@@ -104,21 +102,16 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
end
uri = @dep_uri + name
+ str = Gem::RemoteFetcher.fetcher.fetch_path uri
- begin
- str = Gem::RemoteFetcher.fetcher.fetch_path uri
- rescue Gem::RemoteFetcher::FetchError
- @data[name] = []
- else
- lines(str).each do |ver|
- number, platform, dependencies, requirements = parse_gem(ver)
+ lines(str).each do |ver|
+ number, platform, dependencies, requirements = parse_gem(ver)
- platform ||= "ruby"
- dependencies = dependencies.map {|dep_name, reqs| [dep_name, reqs.join(", ")] }
- requirements = requirements.map {|req_name, reqs| [req_name.to_sym, reqs] }.to_h
+ platform ||= "ruby"
+ dependencies = dependencies.map {|dep_name, reqs| [dep_name, reqs.join(", ")] }
+ requirements = requirements.map {|req_name, reqs| [req_name.to_sym, reqs] }.to_h
- @data[name] << { name: name, number: number, platform: platform, dependencies: dependencies, requirements: requirements }
- end
+ @data[name] << { name: name, number: number, platform: platform, dependencies: dependencies, requirements: requirements }
end
@data[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..1e65d5e5a9 100644
--- a/lib/rubygems/resolver/api_specification.rb
+++ b/lib/rubygems/resolver/api_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Represents a specification retrieved via the rubygems.org API.
#
@@ -22,7 +21,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 e2307f6e02..075ee1ef5c 100644
--- a/lib/rubygems/resolver/best_set.rb
+++ b/lib/rubygems/resolver/best_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The BestSet chooses the best available method to query a remote index.
#
@@ -29,6 +28,10 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
pick_sets if @remote && @sets.empty?
super
+ rescue Gem::RemoteFetcher::FetchError => e
+ replace_failed_api_set e
+
+ retry
end
def prefetch(reqs) # :nodoc:
@@ -46,4 +49,28 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
q.pp @sets
end
end
+
+ ##
+ # Replaces a failed APISet for the URI in +error+ with an IndexSet.
+ #
+ # If no matching APISet can be found the original +error+ is raised.
+ #
+ # The calling method must retry the exception to repeat the lookup.
+
+ def replace_failed_api_set(error) # :nodoc:
+ uri = error.original_uri
+ uri = URI uri unless URI === uri
+ uri = uri + "."
+
+ raise error unless api_set = @sets.find do |set|
+ Gem::Resolver::APISet === set && set.dep_uri == uri
+ end
+
+ index_set = Gem::Resolver::IndexSet.new api_set.source
+
+ @sets.map! do |set|
+ next set unless set == api_set
+ index_set
+ end
+ end
end
diff --git a/lib/rubygems/resolver/composed_set.rb b/lib/rubygems/resolver/composed_set.rb
index 8a714ad447..226da1e1e0 100644
--- a/lib/rubygems/resolver/composed_set.rb
+++ b/lib/rubygems/resolver/composed_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A ComposedSet allows multiple sets to be queried like a single set.
#
@@ -44,7 +43,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..aba6d73ea7 100644
--- a/lib/rubygems/resolver/conflict.rb
+++ b/lib/rubygems/resolver/conflict.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Used internally to indicate that a dependency conflicted
# with a spec that would be activated.
@@ -55,7 +54,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 +63,10 @@ class Gem::Resolver::Conflict
%s
MATCHING
- matching = format(matching, dependency, alternates.join(", "))
+ matching = matching % [
+ dependency,
+ alternates.join(", "),
+ ]
end
explanation = <<-EXPLANATION
@@ -79,7 +81,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 +131,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/current_set.rb b/lib/rubygems/resolver/current_set.rb
index 370e445089..c3aa3a2c37 100644
--- a/lib/rubygems/resolver/current_set.rb
+++ b/lib/rubygems/resolver/current_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A set which represents the installed gems. Respects
# all the normal settings that control where to look
diff --git a/lib/rubygems/resolver/dependency_request.rb b/lib/rubygems/resolver/dependency_request.rb
index 60b338277f..70a61cbc25 100644
--- a/lib/rubygems/resolver/dependency_request.rb
+++ b/lib/rubygems/resolver/dependency_request.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Used Internally. Wraps a Dependency object to also track which spec
# contained the Dependency.
diff --git a/lib/rubygems/resolver/git_set.rb b/lib/rubygems/resolver/git_set.rb
index 89342ff80d..f010273a8f 100644
--- a/lib/rubygems/resolver/git_set.rb
+++ b/lib/rubygems/resolver/git_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A GitSet represents gems that are sourced from git repositories.
#
diff --git a/lib/rubygems/resolver/git_specification.rb b/lib/rubygems/resolver/git_specification.rb
index e587c17d2a..6a178ea82e 100644
--- a/lib/rubygems/resolver/git_specification.rb
+++ b/lib/rubygems/resolver/git_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A GitSpecification represents a gem that is sourced from a git repository
# and is being loaded through a gem dependencies file through the +git:+
diff --git a/lib/rubygems/resolver/index_set.rb b/lib/rubygems/resolver/index_set.rb
index 0b4f376452..2344178314 100644
--- a/lib/rubygems/resolver/index_set.rb
+++ b/lib/rubygems/resolver/index_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The global rubygems pool represented via the traditional
# source index.
@@ -44,10 +43,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..0fc758dfd3 100644
--- a/lib/rubygems/resolver/index_specification.rb
+++ b/lib/rubygems/resolver/index_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Represents a possible Specification object returned from IndexSet. Used to
# delay needed to download full Specification objects when only the +name+
@@ -68,7 +67,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 +75,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..8932e068be 100644
--- a/lib/rubygems/resolver/installed_specification.rb
+++ b/lib/rubygems/resolver/installed_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# An InstalledSpecification represents a gem that is already installed
# locally.
@@ -25,7 +24,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..5e18be50ef 100644
--- a/lib/rubygems/resolver/installer_set.rb
+++ b/lib/rubygems/resolver/installer_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A set of gems for installation sourced from remote sources and local .gem
# files
@@ -148,8 +147,6 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
res << Gem::Resolver::InstalledSpecification.new(self, gemspec)
end unless @ignore_installed
- matching_local = []
-
if consider_local?
matching_local = @local.values.select do |spec, _|
req.match? spec
@@ -163,15 +160,14 @@ 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
end
end
- res.concat @remote_set.find_all req if consider_remote? && matching_local.empty?
+ res.concat @remote_set.find_all req if consider_remote?
res
end
@@ -187,9 +183,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 +261,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..c27bab0f5a 100644
--- a/lib/rubygems/resolver/local_specification.rb
+++ b/lib/rubygems/resolver/local_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A LocalSpecification comes from a .gem file on the local filesystem.
@@ -8,7 +7,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..b1a5433cb5 100644
--- a/lib/rubygems/resolver/lock_set.rb
+++ b/lib/rubygems/resolver/lock_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A set of gems from a gem dependencies lockfile.
@@ -75,7 +74,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/resolver/lock_specification.rb b/lib/rubygems/resolver/lock_specification.rb
index 06f912dd85..7de2a14658 100644
--- a/lib/rubygems/resolver/lock_specification.rb
+++ b/lib/rubygems/resolver/lock_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The LockSpecification comes from a lockfile (Gem::RequestSet::Lockfile).
#
diff --git a/lib/rubygems/resolver/molinillo.rb b/lib/rubygems/resolver/molinillo.rb
new file mode 100644
index 0000000000..e154342571
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo.rb
@@ -0,0 +1,2 @@
+# frozen_string_literal: true
+require_relative "molinillo/lib/molinillo"
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo.rb b/lib/rubygems/resolver/molinillo/lib/molinillo.rb
new file mode 100644
index 0000000000..f67badbde7
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require_relative 'molinillo/gem_metadata'
+require_relative 'molinillo/errors'
+require_relative 'molinillo/resolver'
+require_relative 'molinillo/modules/ui'
+require_relative 'molinillo/modules/specification_provider'
+
+# Gem::Resolver::Molinillo is a generic dependency resolution algorithm.
+module Gem::Resolver::Molinillo
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb
new file mode 100644
index 0000000000..d540d3baff
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # @!visibility private
+ module Delegates
+ # Delegates all {Gem::Resolver::Molinillo::ResolutionState} methods to a `#state` property.
+ module ResolutionState
+ # (see Gem::Resolver::Molinillo::ResolutionState#name)
+ def name
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.name
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#requirements)
+ def requirements
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.requirements
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#activated)
+ def activated
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.activated
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#requirement)
+ def requirement
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.requirement
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#possibilities)
+ def possibilities
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.possibilities
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#depth)
+ def depth
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.depth
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#conflicts)
+ def conflicts
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.conflicts
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#unused_unwind_options)
+ def unused_unwind_options
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.unused_unwind_options
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb
new file mode 100644
index 0000000000..b765226fb0
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ module Delegates
+ # Delegates all {Gem::Resolver::Molinillo::SpecificationProvider} methods to a
+ # `#specification_provider` property.
+ module SpecificationProvider
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#search_for)
+ def search_for(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.search_for(dependency)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#dependencies_for)
+ def dependencies_for(specification)
+ with_no_such_dependency_error_handling do
+ specification_provider.dependencies_for(specification)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#requirement_satisfied_by?)
+ def requirement_satisfied_by?(requirement, activated, spec)
+ with_no_such_dependency_error_handling do
+ specification_provider.requirement_satisfied_by?(requirement, activated, spec)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#dependencies_equal?)
+ def dependencies_equal?(dependencies, other_dependencies)
+ with_no_such_dependency_error_handling do
+ specification_provider.dependencies_equal?(dependencies, other_dependencies)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for)
+ def name_for(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for(dependency)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for_explicit_dependency_source)
+ def name_for_explicit_dependency_source
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for_explicit_dependency_source
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for_locking_dependency_source)
+ def name_for_locking_dependency_source
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for_locking_dependency_source
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#sort_dependencies)
+ def sort_dependencies(dependencies, activated, conflicts)
+ with_no_such_dependency_error_handling do
+ specification_provider.sort_dependencies(dependencies, activated, conflicts)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#allow_missing?)
+ def allow_missing?(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.allow_missing?(dependency)
+ end
+ end
+
+ private
+
+ # Ensures any raised {NoSuchDependencyError} has its
+ # {NoSuchDependencyError#required_by} set.
+ # @yield
+ def with_no_such_dependency_error_handling
+ yield
+ rescue NoSuchDependencyError => error
+ if state
+ vertex = activated.vertex_named(name_for(error.dependency))
+ error.required_by += vertex.incoming_edges.map { |e| e.origin.name }
+ error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty?
+ end
+ raise
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb
new file mode 100644
index 0000000000..731a9e3e90
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb
@@ -0,0 +1,255 @@
+# frozen_string_literal: true
+
+require_relative '../../../../tsort'
+
+require_relative 'dependency_graph/log'
+require_relative 'dependency_graph/vertex'
+
+module Gem::Resolver::Molinillo
+ # A directed acyclic graph that is tuned to hold named dependencies
+ class DependencyGraph
+ include Enumerable
+
+ # Enumerates through the vertices of the graph.
+ # @return [Array<Vertex>] The graph's vertices.
+ def each
+ return vertices.values.each unless block_given?
+ vertices.values.each { |v| yield v }
+ end
+
+ include Gem::TSort
+
+ # @!visibility private
+ alias tsort_each_node each
+
+ # @!visibility private
+ def tsort_each_child(vertex, &block)
+ vertex.successors.each(&block)
+ end
+
+ # Topologically sorts the given vertices.
+ # @param [Enumerable<Vertex>] vertices the vertices to be sorted, which must
+ # all belong to the same graph.
+ # @return [Array<Vertex>] The sorted vertices.
+ def self.tsort(vertices)
+ Gem::TSort.tsort(
+ lambda { |b| vertices.each(&b) },
+ lambda { |v, &b| (v.successors & vertices).each(&b) }
+ )
+ end
+
+ # A directed edge of a {DependencyGraph}
+ # @attr [Vertex] origin The origin of the directed edge
+ # @attr [Vertex] destination The destination of the directed edge
+ # @attr [Object] requirement The requirement the directed edge represents
+ Edge = Struct.new(:origin, :destination, :requirement)
+
+ # @return [{String => Vertex}] the vertices of the dependency graph, keyed
+ # by {Vertex#name}
+ attr_reader :vertices
+
+ # @return [Log] the op log for this graph
+ attr_reader :log
+
+ # Initializes an empty dependency graph
+ def initialize
+ @vertices = {}
+ @log = Log.new
+ end
+
+ # Tags the current state of the dependency as the given tag
+ # @param [Object] tag an opaque tag for the current state of the graph
+ # @return [Void]
+ def tag(tag)
+ log.tag(self, tag)
+ end
+
+ # Rewinds the graph to the state tagged as `tag`
+ # @param [Object] tag the tag to rewind to
+ # @return [Void]
+ def rewind_to(tag)
+ log.rewind_to(self, tag)
+ end
+
+ # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices}
+ # are properly copied.
+ # @param [DependencyGraph] other the graph to copy.
+ def initialize_copy(other)
+ super
+ @vertices = {}
+ @log = other.log.dup
+ traverse = lambda do |new_v, old_v|
+ return if new_v.outgoing_edges.size == old_v.outgoing_edges.size
+ old_v.outgoing_edges.each do |edge|
+ destination = add_vertex(edge.destination.name, edge.destination.payload)
+ add_edge_no_circular(new_v, destination, edge.requirement)
+ traverse.call(destination, edge.destination)
+ end
+ end
+ other.vertices.each do |name, vertex|
+ new_vertex = add_vertex(name, vertex.payload, vertex.root?)
+ new_vertex.explicit_requirements.replace(vertex.explicit_requirements)
+ traverse.call(new_vertex, vertex)
+ end
+ end
+
+ # @return [String] a string suitable for debugging
+ def inspect
+ "#{self.class}:#{vertices.values.inspect}"
+ end
+
+ # @param [Hash] options options for dot output.
+ # @return [String] Returns a dot format representation of the graph
+ def to_dot(options = {})
+ edge_label = options.delete(:edge_label)
+ raise ArgumentError, "Unknown options: #{options.keys}" unless options.empty?
+
+ dot_vertices = []
+ dot_edges = []
+ vertices.each do |n, v|
+ dot_vertices << " #{n} [label=\"{#{n}|#{v.payload}}\"]"
+ v.outgoing_edges.each do |e|
+ label = edge_label ? edge_label.call(e) : e.requirement
+ dot_edges << " #{e.origin.name} -> #{e.destination.name} [label=#{label.to_s.dump}]"
+ end
+ end
+
+ dot_vertices.uniq!
+ dot_vertices.sort!
+ dot_edges.uniq!
+ dot_edges.sort!
+
+ dot = dot_vertices.unshift('digraph G {').push('') + dot_edges.push('}')
+ dot.join("\n")
+ end
+
+ # @param [DependencyGraph] other
+ # @return [Boolean] whether the two dependency graphs are equal, determined
+ # by a recursive traversal of each {#root_vertices} and its
+ # {Vertex#successors}
+ def ==(other)
+ return false unless other
+ return true if equal?(other)
+ vertices.each do |name, vertex|
+ other_vertex = other.vertex_named(name)
+ return false unless other_vertex
+ return false unless vertex.payload == other_vertex.payload
+ return false unless other_vertex.successors.to_set == vertex.successors.to_set
+ end
+ end
+
+ # @param [String] name
+ # @param [Object] payload
+ # @param [Array<String>] parent_names
+ # @param [Object] requirement the requirement that is requiring the child
+ # @return [void]
+ def add_child_vertex(name, payload, parent_names, requirement)
+ root = !parent_names.delete(nil) { true }
+ vertex = add_vertex(name, payload, root)
+ vertex.explicit_requirements << requirement if root
+ parent_names.each do |parent_name|
+ parent_vertex = vertex_named(parent_name)
+ add_edge(parent_vertex, vertex, requirement)
+ end
+ vertex
+ end
+
+ # Adds a vertex with the given name, or updates the existing one.
+ # @param [String] name
+ # @param [Object] payload
+ # @return [Vertex] the vertex that was added to `self`
+ def add_vertex(name, payload, root = false)
+ log.add_vertex(self, name, payload, root)
+ end
+
+ # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
+ # removing any non-root vertices that were orphaned in the process
+ # @param [String] name
+ # @return [Array<Vertex>] the vertices which have been detached
+ def detach_vertex_named(name)
+ log.detach_vertex_named(self, name)
+ end
+
+ # @param [String] name
+ # @return [Vertex,nil] the vertex with the given name
+ def vertex_named(name)
+ vertices[name]
+ end
+
+ # @param [String] name
+ # @return [Vertex,nil] the root vertex with the given name
+ def root_vertex_named(name)
+ vertex = vertex_named(name)
+ vertex if vertex && vertex.root?
+ end
+
+ # Adds a new {Edge} to the dependency graph
+ # @param [Vertex] origin
+ # @param [Vertex] destination
+ # @param [Object] requirement the requirement that this edge represents
+ # @return [Edge] the added edge
+ def add_edge(origin, destination, requirement)
+ if destination.path_to?(origin)
+ raise CircularDependencyError.new(path(destination, origin))
+ end
+ add_edge_no_circular(origin, destination, requirement)
+ end
+
+ # Deletes an {Edge} from the dependency graph
+ # @param [Edge] edge
+ # @return [Void]
+ def delete_edge(edge)
+ log.delete_edge(self, edge.origin.name, edge.destination.name, edge.requirement)
+ end
+
+ # Sets the payload of the vertex with the given name
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload
+ # @return [Void]
+ def set_payload(name, payload)
+ log.set_payload(self, name, payload)
+ end
+
+ private
+
+ # Adds a new {Edge} to the dependency graph without checking for
+ # circularity.
+ # @param (see #add_edge)
+ # @return (see #add_edge)
+ def add_edge_no_circular(origin, destination, requirement)
+ log.add_edge_no_circular(self, origin.name, destination.name, requirement)
+ end
+
+ # Returns the path between two vertices
+ # @raise [ArgumentError] if there is no path between the vertices
+ # @param [Vertex] from
+ # @param [Vertex] to
+ # @return [Array<Vertex>] the shortest path from `from` to `to`
+ def path(from, to)
+ distances = Hash.new(vertices.size + 1)
+ distances[from.name] = 0
+ predecessors = {}
+ each do |vertex|
+ vertex.successors.each do |successor|
+ if distances[successor.name] > distances[vertex.name] + 1
+ distances[successor.name] = distances[vertex.name] + 1
+ predecessors[successor] = vertex
+ end
+ end
+ end
+
+ path = [to]
+ while before = predecessors[to]
+ path << before
+ to = before
+ break if to == from
+ end
+
+ unless path.last.equal?(from)
+ raise ArgumentError, "There is no path from #{from.name} to #{to.name}"
+ end
+
+ path.reverse
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb
new file mode 100644
index 0000000000..cc140031b3
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # An action that modifies a {DependencyGraph} that is reversible.
+ # @abstract
+ class Action
+ # rubocop:disable Lint/UnusedMethodArgument
+
+ # @return [Symbol] The name of the action.
+ def self.action_name
+ raise 'Abstract'
+ end
+
+ # Performs the action on the given graph.
+ # @param [DependencyGraph] graph the graph to perform the action on.
+ # @return [Void]
+ def up(graph)
+ raise 'Abstract'
+ end
+
+ # Reverses the action on the given graph.
+ # @param [DependencyGraph] graph the graph to reverse the action on.
+ # @return [Void]
+ def down(graph)
+ raise 'Abstract'
+ end
+
+ # @return [Action,Nil] The previous action
+ attr_accessor :previous
+
+ # @return [Action,Nil] The next action
+ attr_accessor :next
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
new file mode 100644
index 0000000000..5570483253
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#add_edge_no_circular)
+ class AddEdgeNoCircular < Action
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges << edge
+ edge.destination.incoming_edges << edge
+ edge
+ end
+
+ # (see Action#down)
+ def down(graph)
+ edge = make_edge(graph)
+ delete_first(edge.origin.outgoing_edges, edge)
+ delete_first(edge.destination.incoming_edges, edge)
+ end
+
+ # @!group AddEdgeNoCircular
+
+ # @return [String] the name of the origin of the edge
+ attr_reader :origin
+
+ # @return [String] the name of the destination of the edge
+ attr_reader :destination
+
+ # @return [Object] the requirement that the edge represents
+ attr_reader :requirement
+
+ # @param [DependencyGraph] graph the graph to find vertices from
+ # @return [Edge] The edge this action adds
+ def make_edge(graph)
+ Edge.new(graph.vertex_named(origin), graph.vertex_named(destination), requirement)
+ end
+
+ # Initialize an action to add an edge to a dependency graph
+ # @param [String] origin the name of the origin of the edge
+ # @param [String] destination the name of the destination of the edge
+ # @param [Object] requirement the requirement that the edge represents
+ def initialize(origin, destination, requirement)
+ @origin = origin
+ @destination = destination
+ @requirement = requirement
+ end
+
+ private
+
+ def delete_first(array, item)
+ return unless index = array.index(item)
+ array.delete_at(index)
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
new file mode 100644
index 0000000000..f1411d5efa
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#add_vertex)
+ class AddVertex < Action # :nodoc:
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ if existing = graph.vertices[name]
+ @existing_payload = existing.payload
+ @existing_root = existing.root
+ end
+ vertex = existing || Vertex.new(name, payload)
+ graph.vertices[vertex.name] = vertex
+ vertex.payload ||= payload
+ vertex.root ||= root
+ vertex
+ end
+
+ # (see Action#down)
+ def down(graph)
+ if defined?(@existing_payload)
+ vertex = graph.vertices[name]
+ vertex.payload = @existing_payload
+ vertex.root = @existing_root
+ else
+ graph.vertices.delete(name)
+ end
+ end
+
+ # @!group AddVertex
+
+ # @return [String] the name of the vertex
+ attr_reader :name
+
+ # @return [Object] the payload for the vertex
+ attr_reader :payload
+
+ # @return [Boolean] whether the vertex is root or not
+ attr_reader :root
+
+ # Initialize an action to add a vertex to a dependency graph
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload for the vertex
+ # @param [Boolean] root whether the vertex is root or not
+ def initialize(name, payload, root)
+ @name = name
+ @payload = payload
+ @root = root
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
new file mode 100644
index 0000000000..3b48d77a50
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#delete_edge)
+ class DeleteEdge < Action
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :delete_edge
+ end
+
+ # (see Action#up)
+ def up(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges.delete(edge)
+ edge.destination.incoming_edges.delete(edge)
+ end
+
+ # (see Action#down)
+ def down(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges << edge
+ edge.destination.incoming_edges << edge
+ edge
+ end
+
+ # @!group DeleteEdge
+
+ # @return [String] the name of the origin of the edge
+ attr_reader :origin_name
+
+ # @return [String] the name of the destination of the edge
+ attr_reader :destination_name
+
+ # @return [Object] the requirement that the edge represents
+ attr_reader :requirement
+
+ # @param [DependencyGraph] graph the graph to find vertices from
+ # @return [Edge] The edge this action adds
+ def make_edge(graph)
+ Edge.new(
+ graph.vertex_named(origin_name),
+ graph.vertex_named(destination_name),
+ requirement
+ )
+ end
+
+ # Initialize an action to add an edge to a dependency graph
+ # @param [String] origin_name the name of the origin of the edge
+ # @param [String] destination_name the name of the destination of the edge
+ # @param [Object] requirement the requirement that the edge represents
+ def initialize(origin_name, destination_name, requirement)
+ @origin_name = origin_name
+ @destination_name = destination_name
+ @requirement = requirement
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
new file mode 100644
index 0000000000..92f60d5be8
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#detach_vertex_named
+ class DetachVertexNamed < Action
+ # @!group Action
+
+ # (see Action#name)
+ def self.action_name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ return [] unless @vertex = graph.vertices.delete(name)
+
+ removed_vertices = [@vertex]
+ @vertex.outgoing_edges.each do |e|
+ v = e.destination
+ v.incoming_edges.delete(e)
+ if !v.root? && v.incoming_edges.empty?
+ removed_vertices.concat graph.detach_vertex_named(v.name)
+ end
+ end
+
+ @vertex.incoming_edges.each do |e|
+ v = e.origin
+ v.outgoing_edges.delete(e)
+ end
+
+ removed_vertices
+ end
+
+ # (see Action#down)
+ def down(graph)
+ return unless @vertex
+ graph.vertices[@vertex.name] = @vertex
+ @vertex.outgoing_edges.each do |e|
+ e.destination.incoming_edges << e
+ end
+ @vertex.incoming_edges.each do |e|
+ e.origin.outgoing_edges << e
+ end
+ end
+
+ # @!group DetachVertexNamed
+
+ # @return [String] the name of the vertex to detach
+ attr_reader :name
+
+ # Initialize an action to detach a vertex from a dependency graph
+ # @param [String] name the name of the vertex to detach
+ def initialize(name)
+ @name = name
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb
new file mode 100644
index 0000000000..7aeb8847ec
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require_relative 'add_edge_no_circular'
+require_relative 'add_vertex'
+require_relative 'delete_edge'
+require_relative 'detach_vertex_named'
+require_relative 'set_payload'
+require_relative 'tag'
+
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # A log for dependency graph actions
+ class Log
+ # Initializes an empty log
+ def initialize
+ @current_action = @first_action = nil
+ end
+
+ # @!macro [new] action
+ # {include:DependencyGraph#$0}
+ # @param [Graph] graph the graph to perform the action on
+ # @param (see DependencyGraph#$0)
+ # @return (see DependencyGraph#$0)
+
+ # @macro action
+ def tag(graph, tag)
+ push_action(graph, Tag.new(tag))
+ end
+
+ # @macro action
+ def add_vertex(graph, name, payload, root)
+ push_action(graph, AddVertex.new(name, payload, root))
+ end
+
+ # @macro action
+ def detach_vertex_named(graph, name)
+ push_action(graph, DetachVertexNamed.new(name))
+ end
+
+ # @macro action
+ def add_edge_no_circular(graph, origin, destination, requirement)
+ push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement))
+ end
+
+ # {include:DependencyGraph#delete_edge}
+ # @param [Graph] graph the graph to perform the action on
+ # @param [String] origin_name
+ # @param [String] destination_name
+ # @param [Object] requirement
+ # @return (see DependencyGraph#delete_edge)
+ def delete_edge(graph, origin_name, destination_name, requirement)
+ push_action(graph, DeleteEdge.new(origin_name, destination_name, requirement))
+ end
+
+ # @macro action
+ def set_payload(graph, name, payload)
+ push_action(graph, SetPayload.new(name, payload))
+ end
+
+ # Pops the most recent action from the log and undoes the action
+ # @param [DependencyGraph] graph
+ # @return [Action] the action that was popped off the log
+ def pop!(graph)
+ return unless action = @current_action
+ unless @current_action = action.previous
+ @first_action = nil
+ end
+ action.down(graph)
+ action
+ end
+
+ extend Enumerable
+
+ # @!visibility private
+ # Enumerates each action in the log
+ # @yield [Action]
+ def each
+ return enum_for unless block_given?
+ action = @first_action
+ loop do
+ break unless action
+ yield action
+ action = action.next
+ end
+ self
+ end
+
+ # @!visibility private
+ # Enumerates each action in the log in reverse order
+ # @yield [Action]
+ def reverse_each
+ return enum_for(:reverse_each) unless block_given?
+ action = @current_action
+ loop do
+ break unless action
+ yield action
+ action = action.previous
+ end
+ self
+ end
+
+ # @macro action
+ def rewind_to(graph, tag)
+ loop do
+ action = pop!(graph)
+ raise "No tag #{tag.inspect} found" unless action
+ break if action.class.action_name == :tag && action.tag == tag
+ end
+ end
+
+ private
+
+ # Adds the given action to the log, running the action
+ # @param [DependencyGraph] graph
+ # @param [Action] action
+ # @return The value returned by `action.up`
+ def push_action(graph, action)
+ action.previous = @current_action
+ @current_action.next = action if @current_action
+ @current_action = action
+ @first_action ||= action
+ action.up(graph)
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb
new file mode 100644
index 0000000000..726292a2c3
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#set_payload
+ class SetPayload < Action # :nodoc:
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :set_payload
+ end
+
+ # (see Action#up)
+ def up(graph)
+ vertex = graph.vertex_named(name)
+ @old_payload = vertex.payload
+ vertex.payload = payload
+ end
+
+ # (see Action#down)
+ def down(graph)
+ graph.vertex_named(name).payload = @old_payload
+ end
+
+ # @!group SetPayload
+
+ # @return [String] the name of the vertex
+ attr_reader :name
+
+ # @return [Object] the payload for the vertex
+ attr_reader :payload
+
+ # Initialize an action to add set the payload for a vertex in a dependency
+ # graph
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload for the vertex
+ def initialize(name, payload)
+ @name = name
+ @payload = payload
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb
new file mode 100644
index 0000000000..bfe6fd31f8
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#tag
+ class Tag < Action
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :tag
+ end
+
+ # (see Action#up)
+ def up(graph)
+ end
+
+ # (see Action#down)
+ def down(graph)
+ end
+
+ # @!group Tag
+
+ # @return [Object] An opaque tag
+ attr_reader :tag
+
+ # Initialize an action to tag a state of a dependency graph
+ # @param [Object] tag an opaque tag
+ def initialize(tag)
+ @tag = tag
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb
new file mode 100644
index 0000000000..77114951b2
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb
@@ -0,0 +1,164 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # A vertex in a {DependencyGraph} that encapsulates a {#name} and a
+ # {#payload}
+ class Vertex
+ # @return [String] the name of the vertex
+ attr_accessor :name
+
+ # @return [Object] the payload the vertex holds
+ attr_accessor :payload
+
+ # @return [Array<Object>] the explicit requirements that required
+ # this vertex
+ attr_reader :explicit_requirements
+
+ # @return [Boolean] whether the vertex is considered a root vertex
+ attr_accessor :root
+ alias root? root
+
+ # Initializes a vertex with the given name and payload.
+ # @param [String] name see {#name}
+ # @param [Object] payload see {#payload}
+ def initialize(name, payload)
+ @name = name.frozen? ? name : name.dup.freeze
+ @payload = payload
+ @explicit_requirements = []
+ @outgoing_edges = []
+ @incoming_edges = []
+ end
+
+ # @return [Array<Object>] all of the requirements that required
+ # this vertex
+ def requirements
+ (incoming_edges.map(&:requirement) + explicit_requirements).uniq
+ end
+
+ # @return [Array<Edge>] the edges of {#graph} that have `self` as their
+ # {Edge#origin}
+ attr_accessor :outgoing_edges
+
+ # @return [Array<Edge>] the edges of {#graph} that have `self` as their
+ # {Edge#destination}
+ attr_accessor :incoming_edges
+
+ # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
+ # `self` as their {Edge#destination}
+ def predecessors
+ incoming_edges.map(&:origin)
+ end
+
+ # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
+ # {#descendent?}
+ def recursive_predecessors
+ _recursive_predecessors
+ end
+
+ # @param [Set<Vertex>] vertices the set to add the predecessors to
+ # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
+ # {#descendent?}
+ def _recursive_predecessors(vertices = new_vertex_set)
+ incoming_edges.each do |edge|
+ vertex = edge.origin
+ next unless vertices.add?(vertex)
+ vertex._recursive_predecessors(vertices)
+ end
+
+ vertices
+ end
+ protected :_recursive_predecessors
+
+ # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
+ # `self` as their {Edge#origin}
+ def successors
+ outgoing_edges.map(&:destination)
+ end
+
+ # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
+ # {#ancestor?}
+ def recursive_successors
+ _recursive_successors
+ end
+
+ # @param [Set<Vertex>] vertices the set to add the successors to
+ # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
+ # {#ancestor?}
+ def _recursive_successors(vertices = new_vertex_set)
+ outgoing_edges.each do |edge|
+ vertex = edge.destination
+ next unless vertices.add?(vertex)
+ vertex._recursive_successors(vertices)
+ end
+
+ vertices
+ end
+ protected :_recursive_successors
+
+ # @return [String] a string suitable for debugging
+ def inspect
+ "#{self.class}:#{name}(#{payload.inspect})"
+ end
+
+ # @return [Boolean] whether the two vertices are equal, determined
+ # by a recursive traversal of each {Vertex#successors}
+ def ==(other)
+ return true if equal?(other)
+ shallow_eql?(other) &&
+ successors.to_set == other.successors.to_set
+ end
+
+ # @param [Vertex] other the other vertex to compare to
+ # @return [Boolean] whether the two vertices are equal, determined
+ # solely by {#name} and {#payload} equality
+ def shallow_eql?(other)
+ return true if equal?(other)
+ other &&
+ name == other.name &&
+ payload == other.payload
+ end
+
+ alias eql? ==
+
+ # @return [Fixnum] a hash for the vertex based upon its {#name}
+ def hash
+ name.hash
+ end
+
+ # Is there a path from `self` to `other` following edges in the
+ # dependency graph?
+ # @return whether there is a path following edges within this {#graph}
+ def path_to?(other)
+ _path_to?(other)
+ end
+
+ alias descendent? path_to?
+
+ # @param [Vertex] other the vertex to check if there's a path to
+ # @param [Set<Vertex>] visited the vertices of {#graph} that have been visited
+ # @return [Boolean] whether there is a path to `other` from `self`
+ def _path_to?(other, visited = new_vertex_set)
+ return false unless visited.add?(self)
+ return true if equal?(other)
+ successors.any? { |v| v._path_to?(other, visited) }
+ end
+ protected :_path_to?
+
+ # Is there a path from `other` to `self` following edges in the
+ # dependency graph?
+ # @return whether there is a path following edges within this {#graph}
+ def ancestor?(other)
+ other.path_to?(self)
+ end
+
+ alias is_reachable_from? ancestor?
+
+ def new_vertex_set
+ require 'set'
+ Set.new
+ end
+ private :new_vertex_set
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb
new file mode 100644
index 0000000000..4289902828
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb
@@ -0,0 +1,149 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # An error that occurred during the resolution process
+ class ResolverError < StandardError; end
+
+ # An error caused by searching for a dependency that is completely unknown,
+ # i.e. has no versions available whatsoever.
+ class NoSuchDependencyError < ResolverError
+ # @return [Object] the dependency that could not be found
+ attr_accessor :dependency
+
+ # @return [Array<Object>] the specifications that depended upon {#dependency}
+ attr_accessor :required_by
+
+ # Initializes a new error with the given missing dependency.
+ # @param [Object] dependency @see {#dependency}
+ # @param [Array<Object>] required_by @see {#required_by}
+ def initialize(dependency, required_by = [])
+ @dependency = dependency
+ @required_by = required_by.uniq
+ super()
+ end
+
+ # The error message for the missing dependency, including the specifications
+ # that had this dependency.
+ def message
+ sources = required_by.map { |r| "`#{r}`" }.join(' and ')
+ message = "Unable to find a specification for `#{dependency}`"
+ message += " depended upon by #{sources}" unless sources.empty?
+ message
+ end
+ end
+
+ # An error caused by attempting to fulfil a dependency that was circular
+ #
+ # @note This exception will be thrown if and only if a {Vertex} is added to a
+ # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an
+ # existing {DependencyGraph::Vertex}
+ class CircularDependencyError < ResolverError
+ # [Set<Object>] the dependencies responsible for causing the error
+ attr_reader :dependencies
+
+ # Initializes a new error with the given circular vertices.
+ # @param [Array<DependencyGraph::Vertex>] vertices the vertices in the dependency
+ # that caused the error
+ def initialize(vertices)
+ super "There is a circular dependency between #{vertices.map(&:name).join(' and ')}"
+ @dependencies = vertices.map { |vertex| vertex.payload.possibilities.last }.to_set
+ end
+ end
+
+ # An error caused by conflicts in version
+ class VersionConflict < ResolverError
+ # @return [{String => Resolution::Conflict}] the conflicts that caused
+ # resolution to fail
+ attr_reader :conflicts
+
+ # @return [SpecificationProvider] the specification provider used during
+ # resolution
+ attr_reader :specification_provider
+
+ # Initializes a new error with the given version conflicts.
+ # @param [{String => Resolution::Conflict}] conflicts see {#conflicts}
+ # @param [SpecificationProvider] specification_provider see {#specification_provider}
+ def initialize(conflicts, specification_provider)
+ pairs = []
+ conflicts.values.flat_map(&:requirements).each do |conflicting|
+ conflicting.each do |source, conflict_requirements|
+ conflict_requirements.each do |c|
+ pairs << [c, source]
+ end
+ end
+ end
+
+ super "Unable to satisfy the following requirements:\n\n" \
+ "#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}"
+
+ @conflicts = conflicts
+ @specification_provider = specification_provider
+ end
+
+ require_relative 'delegates/specification_provider'
+ include Delegates::SpecificationProvider
+
+ # @return [String] An error message that includes requirement trees,
+ # which is much more detailed & customizable than the default message
+ # @param [Hash] opts the options to create a message with.
+ # @option opts [String] :solver_name The user-facing name of the solver
+ # @option opts [String] :possibility_type The generic name of a possibility
+ # @option opts [Proc] :reduce_trees A proc that reduced the list of requirement trees
+ # @option opts [Proc] :printable_requirement A proc that pretty-prints requirements
+ # @option opts [Proc] :additional_message_for_conflict A proc that appends additional
+ # messages for each conflict
+ # @option opts [Proc] :version_for_spec A proc that returns the version number for a
+ # possibility
+ def message_with_trees(opts = {})
+ solver_name = opts.delete(:solver_name) { self.class.name.split('::').first }
+ possibility_type = opts.delete(:possibility_type) { 'possibility named' }
+ reduce_trees = opts.delete(:reduce_trees) { proc { |trees| trees.uniq.sort_by(&:to_s) } }
+ printable_requirement = opts.delete(:printable_requirement) { proc { |req| req.to_s } }
+ additional_message_for_conflict = opts.delete(:additional_message_for_conflict) { proc {} }
+ version_for_spec = opts.delete(:version_for_spec) { proc(&:to_s) }
+ incompatible_version_message_for_conflict = opts.delete(:incompatible_version_message_for_conflict) do
+ proc do |name, _conflict|
+ %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
+ end
+ end
+
+ full_message_for_conflict = opts.delete(:full_message_for_conflict) do
+ proc do |name, conflict|
+ o = "\n".dup << incompatible_version_message_for_conflict.call(name, conflict) << "\n"
+ if conflict.locked_requirement
+ o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
+ o << %( #{printable_requirement.call(conflict.locked_requirement)}\n)
+ o << %(\n)
+ end
+ o << %( In #{name_for_explicit_dependency_source}:\n)
+ trees = reduce_trees.call(conflict.requirement_trees)
+
+ o << trees.map do |tree|
+ t = ''.dup
+ depth = 2
+ tree.each do |req|
+ t << ' ' * depth << printable_requirement.call(req)
+ unless tree.last == req
+ if spec = conflict.activated_by_name[name_for(req)]
+ t << %( was resolved to #{version_for_spec.call(spec)}, which)
+ end
+ t << %( depends on)
+ end
+ t << %(\n)
+ depth += 1
+ end
+ t
+ end.join("\n")
+
+ additional_message_for_conflict.call(o, name, conflict)
+
+ o
+ end
+ end
+
+ conflicts.sort.reduce(''.dup) do |o, (name, conflict)|
+ o << full_message_for_conflict.call(name, conflict)
+ end.strip
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb
new file mode 100644
index 0000000000..86c249c404
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # The version of Gem::Resolver::Molinillo.
+ VERSION = '0.8.0'.freeze
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb
new file mode 100644
index 0000000000..1067bf7439
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # Provides information about specifications and dependencies to the resolver,
+ # allowing the {Resolver} class to remain generic while still providing power
+ # and flexibility.
+ #
+ # This module contains the methods that users of Gem::Resolver::Molinillo must to implement,
+ # using knowledge of their own model classes.
+ module SpecificationProvider
+ # Search for the specifications that match the given dependency.
+ # The specifications in the returned array will be considered in reverse
+ # order, so the latest version ought to be last.
+ # @note This method should be 'pure', i.e. the return value should depend
+ # only on the `dependency` parameter.
+ #
+ # @param [Object] dependency
+ # @return [Array<Object>] the specifications that satisfy the given
+ # `dependency`.
+ def search_for(dependency)
+ []
+ end
+
+ # Returns the dependencies of `specification`.
+ # @note This method should be 'pure', i.e. the return value should depend
+ # only on the `specification` parameter.
+ #
+ # @param [Object] specification
+ # @return [Array<Object>] the dependencies that are required by the given
+ # `specification`.
+ def dependencies_for(specification)
+ []
+ end
+
+ # Determines whether the given `requirement` is satisfied by the given
+ # `spec`, in the context of the current `activated` dependency graph.
+ #
+ # @param [Object] requirement
+ # @param [DependencyGraph] activated the current dependency graph in the
+ # resolution process.
+ # @param [Object] spec
+ # @return [Boolean] whether `requirement` is satisfied by `spec` in the
+ # context of the current `activated` dependency graph.
+ def requirement_satisfied_by?(requirement, activated, spec)
+ true
+ end
+
+ # Determines whether two arrays of dependencies are equal, and thus can be
+ # grouped.
+ #
+ # @param [Array<Object>] dependencies
+ # @param [Array<Object>] other_dependencies
+ # @return [Boolean] whether `dependencies` and `other_dependencies` should
+ # be considered equal.
+ def dependencies_equal?(dependencies, other_dependencies)
+ dependencies == other_dependencies
+ end
+
+ # Returns the name for the given `dependency`.
+ # @note This method should be 'pure', i.e. the return value should depend
+ # only on the `dependency` parameter.
+ #
+ # @param [Object] dependency
+ # @return [String] the name for the given `dependency`.
+ def name_for(dependency)
+ dependency.to_s
+ end
+
+ # @return [String] the name of the source of explicit dependencies, i.e.
+ # those passed to {Resolver#resolve} directly.
+ def name_for_explicit_dependency_source
+ 'user-specified dependency'
+ end
+
+ # @return [String] the name of the source of 'locked' dependencies, i.e.
+ # those passed to {Resolver#resolve} directly as the `base`
+ def name_for_locking_dependency_source
+ 'Lockfile'
+ end
+
+ # Sort dependencies so that the ones that are easiest to resolve are first.
+ # Easiest to resolve is (usually) defined by:
+ # 1) Is this dependency already activated?
+ # 2) How relaxed are the requirements?
+ # 3) Are there any conflicts for this dependency?
+ # 4) How many possibilities are there to satisfy this dependency?
+ #
+ # @param [Array<Object>] dependencies
+ # @param [DependencyGraph] activated the current dependency graph in the
+ # resolution process.
+ # @param [{String => Array<Conflict>}] conflicts
+ # @return [Array<Object>] a sorted copy of `dependencies`.
+ def sort_dependencies(dependencies, activated, conflicts)
+ dependencies.sort_by do |dependency|
+ name = name_for(dependency)
+ [
+ activated.vertex_named(name).payload ? 0 : 1,
+ conflicts[name] ? 0 : 1,
+ ]
+ end
+ end
+
+ # Returns whether this dependency, which has no possible matching
+ # specifications, can safely be ignored.
+ #
+ # @param [Object] dependency
+ # @return [Boolean] whether this dependency can safely be skipped.
+ def allow_missing?(dependency)
+ false
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb
new file mode 100644
index 0000000000..a810fd519c
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # Conveys information about the resolution process to a user.
+ module UI
+ # The {IO} object that should be used to print output. `STDOUT`, by default.
+ #
+ # @return [IO]
+ def output
+ STDOUT
+ end
+
+ # Called roughly every {#progress_rate}, this method should convey progress
+ # to the user.
+ #
+ # @return [void]
+ def indicate_progress
+ output.print '.' unless debug?
+ end
+
+ # How often progress should be conveyed to the user via
+ # {#indicate_progress}, in seconds. A third of a second, by default.
+ #
+ # @return [Float]
+ def progress_rate
+ 0.33
+ end
+
+ # Called before resolution begins.
+ #
+ # @return [void]
+ def before_resolution
+ output.print 'Resolving dependencies...'
+ end
+
+ # Called after resolution ends (either successfully or with an error).
+ # By default, prints a newline.
+ #
+ # @return [void]
+ def after_resolution
+ output.puts
+ end
+
+ # Conveys debug information to the user.
+ #
+ # @param [Integer] depth the current depth of the resolution process.
+ # @return [void]
+ def debug(depth = 0)
+ if debug?
+ debug_info = yield
+ debug_info = debug_info.inspect unless debug_info.is_a?(String)
+ debug_info = debug_info.split("\n").map { |s| ":#{depth.to_s.rjust 4}: #{s}" }
+ output.puts debug_info
+ end
+ end
+
+ # Whether or not debug messages should be printed.
+ # By default, whether or not the `MOLINILLO_DEBUG` environment variable is
+ # set.
+ #
+ # @return [Boolean]
+ def debug?
+ return @debug_mode if defined?(@debug_mode)
+ @debug_mode = ENV['MOLINILLO_DEBUG']
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb
new file mode 100644
index 0000000000..8b40e59e42
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb
@@ -0,0 +1,839 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ class Resolver
+ # A specific resolution from a given {Resolver}
+ class Resolution
+ # A conflict that the resolution process encountered
+ # @attr [Object] requirement the requirement that immediately led to the conflict
+ # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict
+ # @attr [Object, nil] existing the existing spec that was in conflict with
+ # the {#possibility}
+ # @attr [Object] possibility_set the set of specs that was unable to be
+ # activated due to a conflict.
+ # @attr [Object] locked_requirement the relevant locking requirement.
+ # @attr [Array<Array<Object>>] requirement_trees the different requirement
+ # trees that led to every requirement for the conflicting name.
+ # @attr [{String=>Object}] activated_by_name the already-activated specs.
+ # @attr [Object] underlying_error an error that has occurred during resolution, and
+ # will be raised at the end of it if no resolution is found.
+ Conflict = Struct.new(
+ :requirement,
+ :requirements,
+ :existing,
+ :possibility_set,
+ :locked_requirement,
+ :requirement_trees,
+ :activated_by_name,
+ :underlying_error
+ )
+
+ class Conflict
+ # @return [Object] a spec that was unable to be activated due to a conflict
+ def possibility
+ possibility_set && possibility_set.latest_version
+ end
+ end
+
+ # A collection of possibility states that share the same dependencies
+ # @attr [Array] dependencies the dependencies for this set of possibilities
+ # @attr [Array] possibilities the possibilities
+ PossibilitySet = Struct.new(:dependencies, :possibilities)
+
+ class PossibilitySet
+ # String representation of the possibility set, for debugging
+ def to_s
+ "[#{possibilities.join(', ')}]"
+ end
+
+ # @return [Object] most up-to-date dependency in the possibility set
+ def latest_version
+ possibilities.last
+ end
+ end
+
+ # Details of the state to unwind to when a conflict occurs, and the cause of the unwind
+ # @attr [Integer] state_index the index of the state to unwind to
+ # @attr [Object] state_requirement the requirement of the state we're unwinding to
+ # @attr [Array] requirement_tree for the requirement we're relaxing
+ # @attr [Array] conflicting_requirements the requirements that combined to cause the conflict
+ # @attr [Array] requirement_trees for the conflict
+ # @attr [Array] requirements_unwound_to_instead array of unwind requirements that were chosen over this unwind
+ UnwindDetails = Struct.new(
+ :state_index,
+ :state_requirement,
+ :requirement_tree,
+ :conflicting_requirements,
+ :requirement_trees,
+ :requirements_unwound_to_instead
+ )
+
+ class UnwindDetails
+ include Comparable
+
+ # We compare UnwindDetails when choosing which state to unwind to. If
+ # two options have the same state_index we prefer the one most
+ # removed from a requirement that caused the conflict. Both options
+ # would unwind to the same state, but a `grandparent` option will
+ # filter out fewer of its possibilities after doing so - where a state
+ # is both a `parent` and a `grandparent` to requirements that have
+ # caused a conflict this is the correct behaviour.
+ # @param [UnwindDetail] other UnwindDetail to be compared
+ # @return [Integer] integer specifying ordering
+ def <=>(other)
+ if state_index > other.state_index
+ 1
+ elsif state_index == other.state_index
+ reversed_requirement_tree_index <=> other.reversed_requirement_tree_index
+ else
+ -1
+ end
+ end
+
+ # @return [Integer] index of state requirement in reversed requirement tree
+ # (the conflicting requirement itself will be at position 0)
+ def reversed_requirement_tree_index
+ @reversed_requirement_tree_index ||=
+ if state_requirement
+ requirement_tree.reverse.index(state_requirement)
+ else
+ 999_999
+ end
+ end
+
+ # @return [Boolean] where the requirement of the state we're unwinding
+ # to directly caused the conflict. Note: in this case, it is
+ # impossible for the state we're unwinding to to be a parent of
+ # any of the other conflicting requirements (or we would have
+ # circularity)
+ def unwinding_to_primary_requirement?
+ requirement_tree.last == state_requirement
+ end
+
+ # @return [Array] array of sub-dependencies to avoid when choosing a
+ # new possibility for the state we've unwound to. Only relevant for
+ # non-primary unwinds
+ def sub_dependencies_to_avoid
+ @requirements_to_avoid ||=
+ requirement_trees.map do |tree|
+ index = tree.index(state_requirement)
+ tree[index + 1] if index
+ end.compact
+ end
+
+ # @return [Array] array of all the requirements that led to the need for
+ # this unwind
+ def all_requirements
+ @all_requirements ||= requirement_trees.flatten(1)
+ end
+ end
+
+ # @return [SpecificationProvider] the provider that knows about
+ # dependencies, requirements, specifications, versions, etc.
+ attr_reader :specification_provider
+
+ # @return [UI] the UI that knows how to communicate feedback about the
+ # resolution process back to the user
+ attr_reader :resolver_ui
+
+ # @return [DependencyGraph] the base dependency graph to which
+ # dependencies should be 'locked'
+ attr_reader :base
+
+ # @return [Array] the dependencies that were explicitly required
+ attr_reader :original_requested
+
+ # Initializes a new resolution.
+ # @param [SpecificationProvider] specification_provider
+ # see {#specification_provider}
+ # @param [UI] resolver_ui see {#resolver_ui}
+ # @param [Array] requested see {#original_requested}
+ # @param [DependencyGraph] base see {#base}
+ def initialize(specification_provider, resolver_ui, requested, base)
+ @specification_provider = specification_provider
+ @resolver_ui = resolver_ui
+ @original_requested = requested
+ @base = base
+ @states = []
+ @iteration_counter = 0
+ @parents_of = Hash.new { |h, k| h[k] = [] }
+ end
+
+ # Resolves the {#original_requested} dependencies into a full dependency
+ # graph
+ # @raise [ResolverError] if successful resolution is impossible
+ # @return [DependencyGraph] the dependency graph of successfully resolved
+ # dependencies
+ def resolve
+ start_resolution
+
+ while state
+ break if !state.requirement && state.requirements.empty?
+ indicate_progress
+ if state.respond_to?(:pop_possibility_state) # DependencyState
+ debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" }
+ state.pop_possibility_state.tap do |s|
+ if s
+ states.push(s)
+ activated.tag(s)
+ end
+ end
+ end
+ process_topmost_state
+ end
+
+ resolve_activated_specs
+ ensure
+ end_resolution
+ end
+
+ # @return [Integer] the number of resolver iterations in between calls to
+ # {#resolver_ui}'s {UI#indicate_progress} method
+ attr_accessor :iteration_rate
+ private :iteration_rate
+
+ # @return [Time] the time at which resolution began
+ attr_accessor :started_at
+ private :started_at
+
+ # @return [Array<ResolutionState>] the stack of states for the resolution
+ attr_accessor :states
+ private :states
+
+ private
+
+ # Sets up the resolution process
+ # @return [void]
+ def start_resolution
+ @started_at = Time.now
+
+ push_initial_state
+
+ debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" }
+ resolver_ui.before_resolution
+ end
+
+ def resolve_activated_specs
+ activated.vertices.each do |_, vertex|
+ next unless vertex.payload
+
+ latest_version = vertex.payload.possibilities.reverse_each.find do |possibility|
+ vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) }
+ end
+
+ activated.set_payload(vertex.name, latest_version)
+ end
+ activated.freeze
+ end
+
+ # Ends the resolution process
+ # @return [void]
+ def end_resolution
+ resolver_ui.after_resolution
+ debug do
+ "Finished resolution (#{@iteration_counter} steps) " \
+ "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})"
+ end
+ debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state
+ debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state
+ end
+
+ require_relative 'state'
+ require_relative 'modules/specification_provider'
+
+ require_relative 'delegates/resolution_state'
+ require_relative 'delegates/specification_provider'
+
+ include Gem::Resolver::Molinillo::Delegates::ResolutionState
+ include Gem::Resolver::Molinillo::Delegates::SpecificationProvider
+
+ # Processes the topmost available {RequirementState} on the stack
+ # @return [void]
+ def process_topmost_state
+ if possibility
+ attempt_to_activate
+ else
+ create_conflict
+ unwind_for_conflict
+ end
+ rescue CircularDependencyError => underlying_error
+ create_conflict(underlying_error)
+ unwind_for_conflict
+ end
+
+ # @return [Object] the current possibility that the resolution is trying
+ # to activate
+ def possibility
+ possibilities.last
+ end
+
+ # @return [RequirementState] the current state the resolution is
+ # operating upon
+ def state
+ states.last
+ end
+
+ # Creates and pushes the initial state for the resolution, based upon the
+ # {#requested} dependencies
+ # @return [void]
+ def push_initial_state
+ graph = DependencyGraph.new.tap do |dg|
+ original_requested.each do |requested|
+ vertex = dg.add_vertex(name_for(requested), nil, true)
+ vertex.explicit_requirements << requested
+ end
+ dg.tag(:initial_state)
+ end
+
+ push_state_for_requirements(original_requested, true, graph)
+ end
+
+ # Unwinds the states stack because a conflict has been encountered
+ # @return [void]
+ def unwind_for_conflict
+ details_for_unwind = build_details_for_unwind
+ unwind_options = unused_unwind_options
+ debug(depth) { "Unwinding for conflict: #{requirement} to #{details_for_unwind.state_index / 2}" }
+ conflicts.tap do |c|
+ sliced_states = states.slice!((details_for_unwind.state_index + 1)..-1)
+ raise_error_unless_state(c)
+ activated.rewind_to(sliced_states.first || :initial_state) if sliced_states
+ state.conflicts = c
+ state.unused_unwind_options = unwind_options
+ filter_possibilities_after_unwind(details_for_unwind)
+ index = states.size - 1
+ @parents_of.each { |_, a| a.reject! { |i| i >= index } }
+ state.unused_unwind_options.reject! { |uw| uw.state_index >= index }
+ end
+ end
+
+ # Raises a VersionConflict error, or any underlying error, if there is no
+ # current state
+ # @return [void]
+ def raise_error_unless_state(conflicts)
+ return if state
+
+ error = conflicts.values.map(&:underlying_error).compact.first
+ raise error || VersionConflict.new(conflicts, specification_provider)
+ end
+
+ # @return [UnwindDetails] Details of the nearest index to which we could unwind
+ def build_details_for_unwind
+ # Get the possible unwinds for the current conflict
+ current_conflict = conflicts[name]
+ binding_requirements = binding_requirements_for_conflict(current_conflict)
+ unwind_details = unwind_options_for_requirements(binding_requirements)
+
+ last_detail_for_current_unwind = unwind_details.sort.last
+ current_detail = last_detail_for_current_unwind
+
+ # Look for past conflicts that could be unwound to affect the
+ # requirement tree for the current conflict
+ all_reqs = last_detail_for_current_unwind.all_requirements
+ all_reqs_size = all_reqs.size
+ relevant_unused_unwinds = unused_unwind_options.select do |alternative|
+ diff_reqs = all_reqs - alternative.requirements_unwound_to_instead
+ next if diff_reqs.size == all_reqs_size
+ # Find the highest index unwind whilst looping through
+ current_detail = alternative if alternative > current_detail
+ alternative
+ end
+
+ # Add the current unwind options to the `unused_unwind_options` array.
+ # The "used" option will be filtered out during `unwind_for_conflict`.
+ state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 }
+
+ # Update the requirements_unwound_to_instead on any relevant unused unwinds
+ relevant_unused_unwinds.each do |d|
+ (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
+ end
+ unwind_details.each do |d|
+ (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
+ end
+
+ current_detail
+ end
+
+ # @param [Array<Object>] binding_requirements array of requirements that combine to create a conflict
+ # @return [Array<UnwindDetails>] array of UnwindDetails that have a chance
+ # of resolving the passed requirements
+ def unwind_options_for_requirements(binding_requirements)
+ unwind_details = []
+
+ trees = []
+ binding_requirements.reverse_each do |r|
+ partial_tree = [r]
+ trees << partial_tree
+ unwind_details << UnwindDetails.new(-1, nil, partial_tree, binding_requirements, trees, [])
+
+ # If this requirement has alternative possibilities, check if any would
+ # satisfy the other requirements that created this conflict
+ requirement_state = find_state_for(r)
+ if conflict_fixing_possibilities?(requirement_state, binding_requirements)
+ unwind_details << UnwindDetails.new(
+ states.index(requirement_state),
+ r,
+ partial_tree,
+ binding_requirements,
+ trees,
+ []
+ )
+ end
+
+ # Next, look at the parent of this requirement, and check if the requirement
+ # could have been avoided if an alternative PossibilitySet had been chosen
+ parent_r = parent_of(r)
+ next if parent_r.nil?
+ partial_tree.unshift(parent_r)
+ requirement_state = find_state_for(parent_r)
+ if requirement_state.possibilities.any? { |set| !set.dependencies.include?(r) }
+ unwind_details << UnwindDetails.new(
+ states.index(requirement_state),
+ parent_r,
+ partial_tree,
+ binding_requirements,
+ trees,
+ []
+ )
+ end
+
+ # Finally, look at the grandparent and up of this requirement, looking
+ # for any possibilities that wouldn't create their parent requirement
+ grandparent_r = parent_of(parent_r)
+ until grandparent_r.nil?
+ partial_tree.unshift(grandparent_r)
+ requirement_state = find_state_for(grandparent_r)
+ if requirement_state.possibilities.any? { |set| !set.dependencies.include?(parent_r) }
+ unwind_details << UnwindDetails.new(
+ states.index(requirement_state),
+ grandparent_r,
+ partial_tree,
+ binding_requirements,
+ trees,
+ []
+ )
+ end
+ parent_r = grandparent_r
+ grandparent_r = parent_of(parent_r)
+ end
+ end
+
+ unwind_details
+ end
+
+ # @param [DependencyState] state
+ # @param [Array] binding_requirements array of requirements
+ # @return [Boolean] whether or not the given state has any possibilities
+ # that could satisfy the given requirements
+ def conflict_fixing_possibilities?(state, binding_requirements)
+ return false unless state
+
+ state.possibilities.any? do |possibility_set|
+ possibility_set.possibilities.any? do |poss|
+ possibility_satisfies_requirements?(poss, binding_requirements)
+ end
+ end
+ end
+
+ # Filter's a state's possibilities to remove any that would not fix the
+ # conflict we've just rewound from
+ # @param [UnwindDetails] unwind_details details of the conflict just
+ # unwound from
+ # @return [void]
+ def filter_possibilities_after_unwind(unwind_details)
+ return unless state && !state.possibilities.empty?
+
+ if unwind_details.unwinding_to_primary_requirement?
+ filter_possibilities_for_primary_unwind(unwind_details)
+ else
+ filter_possibilities_for_parent_unwind(unwind_details)
+ end
+ end
+
+ # Filter's a state's possibilities to remove any that would not satisfy
+ # the requirements in the conflict we've just rewound from
+ # @param [UnwindDetails] unwind_details details of the conflict just unwound from
+ # @return [void]
+ def filter_possibilities_for_primary_unwind(unwind_details)
+ unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
+ unwinds_to_state << unwind_details
+ unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements)
+
+ state.possibilities.reject! do |possibility_set|
+ possibility_set.possibilities.none? do |poss|
+ unwind_requirement_sets.any? do |requirements|
+ possibility_satisfies_requirements?(poss, requirements)
+ end
+ end
+ end
+ end
+
+ # @param [Object] possibility a single possibility
+ # @param [Array] requirements an array of requirements
+ # @return [Boolean] whether the possibility satisfies all of the
+ # given requirements
+ def possibility_satisfies_requirements?(possibility, requirements)
+ name = name_for(possibility)
+
+ activated.tag(:swap)
+ activated.set_payload(name, possibility) if activated.vertex_named(name)
+ satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) }
+ activated.rewind_to(:swap)
+
+ satisfied
+ end
+
+ # Filter's a state's possibilities to remove any that would (eventually)
+ # create a requirement in the conflict we've just rewound from
+ # @param [UnwindDetails] unwind_details details of the conflict just unwound from
+ # @return [void]
+ def filter_possibilities_for_parent_unwind(unwind_details)
+ unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
+ unwinds_to_state << unwind_details
+
+ primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq
+ parent_unwinds = unwinds_to_state.uniq - primary_unwinds
+
+ allowed_possibility_sets = primary_unwinds.flat_map do |unwind|
+ states[unwind.state_index].possibilities.select do |possibility_set|
+ possibility_set.possibilities.any? do |poss|
+ possibility_satisfies_requirements?(poss, unwind.conflicting_requirements)
+ end
+ end
+ end
+
+ requirements_to_avoid = parent_unwinds.flat_map(&:sub_dependencies_to_avoid)
+
+ state.possibilities.reject! do |possibility_set|
+ !allowed_possibility_sets.include?(possibility_set) &&
+ (requirements_to_avoid - possibility_set.dependencies).empty?
+ end
+ end
+
+ # @param [Conflict] conflict
+ # @return [Array] minimal array of requirements that would cause the passed
+ # conflict to occur.
+ def binding_requirements_for_conflict(conflict)
+ return [conflict.requirement] if conflict.possibility.nil?
+
+ possible_binding_requirements = conflict.requirements.values.flatten(1).uniq
+
+ # When there's a `CircularDependency` error the conflicting requirement
+ # (the one causing the circular) won't be `conflict.requirement`
+ # (which won't be for the right state, because we won't have created it,
+ # because it's circular).
+ # We need to make sure we have that requirement in the conflict's list,
+ # otherwise we won't be able to unwind properly, so we just return all
+ # the requirements for the conflict.
+ return possible_binding_requirements if conflict.underlying_error
+
+ possibilities = search_for(conflict.requirement)
+
+ # If all the requirements together don't filter out all possibilities,
+ # then the only two requirements we need to consider are the initial one
+ # (where the dependency's version was first chosen) and the last
+ if binding_requirement_in_set?(nil, possible_binding_requirements, possibilities)
+ return [conflict.requirement, requirement_for_existing_name(name_for(conflict.requirement))].compact
+ end
+
+ # Loop through the possible binding requirements, removing each one
+ # that doesn't bind. Use a `reverse_each` as we want the earliest set of
+ # binding requirements, and don't use `reject!` as we wish to refine the
+ # array *on each iteration*.
+ binding_requirements = possible_binding_requirements.dup
+ possible_binding_requirements.reverse_each do |req|
+ next if req == conflict.requirement
+ unless binding_requirement_in_set?(req, binding_requirements, possibilities)
+ binding_requirements -= [req]
+ end
+ end
+
+ binding_requirements
+ end
+
+ # @param [Object] requirement we wish to check
+ # @param [Array] possible_binding_requirements array of requirements
+ # @param [Array] possibilities array of possibilities the requirements will be used to filter
+ # @return [Boolean] whether or not the given requirement is required to filter
+ # out all elements of the array of possibilities.
+ def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities)
+ possibilities.any? do |poss|
+ possibility_satisfies_requirements?(poss, possible_binding_requirements - [requirement])
+ end
+ end
+
+ # @param [Object] requirement
+ # @return [Object] the requirement that led to `requirement` being added
+ # to the list of requirements.
+ def parent_of(requirement)
+ return unless requirement
+ return unless index = @parents_of[requirement].last
+ return unless parent_state = @states[index]
+ parent_state.requirement
+ end
+
+ # @param [String] name
+ # @return [Object] the requirement that led to a version of a possibility
+ # with the given name being activated.
+ def requirement_for_existing_name(name)
+ return nil unless vertex = activated.vertex_named(name)
+ return nil unless vertex.payload
+ states.find { |s| s.name == name }.requirement
+ end
+
+ # @param [Object] requirement
+ # @return [ResolutionState] the state whose `requirement` is the given
+ # `requirement`.
+ def find_state_for(requirement)
+ return nil unless requirement
+ states.find { |i| requirement == i.requirement }
+ end
+
+ # @param [Object] underlying_error
+ # @return [Conflict] a {Conflict} that reflects the failure to activate
+ # the {#possibility} in conjunction with the current {#state}
+ def create_conflict(underlying_error = nil)
+ vertex = activated.vertex_named(name)
+ locked_requirement = locked_requirement_named(name)
+
+ requirements = {}
+ unless vertex.explicit_requirements.empty?
+ requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements
+ end
+ requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement
+ vertex.incoming_edges.each do |edge|
+ (requirements[edge.origin.payload.latest_version] ||= []).unshift(edge.requirement)
+ end
+
+ activated_by_name = {}
+ activated.each { |v| activated_by_name[v.name] = v.payload.latest_version if v.payload }
+ conflicts[name] = Conflict.new(
+ requirement,
+ requirements,
+ vertex.payload && vertex.payload.latest_version,
+ possibility,
+ locked_requirement,
+ requirement_trees,
+ activated_by_name,
+ underlying_error
+ )
+ end
+
+ # @return [Array<Array<Object>>] The different requirement
+ # trees that led to every requirement for the current spec.
+ def requirement_trees
+ vertex = activated.vertex_named(name)
+ vertex.requirements.map { |r| requirement_tree_for(r) }
+ end
+
+ # @param [Object] requirement
+ # @return [Array<Object>] the list of requirements that led to
+ # `requirement` being required.
+ def requirement_tree_for(requirement)
+ tree = []
+ while requirement
+ tree.unshift(requirement)
+ requirement = parent_of(requirement)
+ end
+ tree
+ end
+
+ # Indicates progress roughly once every second
+ # @return [void]
+ def indicate_progress
+ @iteration_counter += 1
+ @progress_rate ||= resolver_ui.progress_rate
+ if iteration_rate.nil?
+ if Time.now - started_at >= @progress_rate
+ self.iteration_rate = @iteration_counter
+ end
+ end
+
+ if iteration_rate && (@iteration_counter % iteration_rate) == 0
+ resolver_ui.indicate_progress
+ end
+ end
+
+ # Calls the {#resolver_ui}'s {UI#debug} method
+ # @param [Integer] depth the depth of the {#states} stack
+ # @param [Proc] block a block that yields a {#to_s}
+ # @return [void]
+ def debug(depth = 0, &block)
+ resolver_ui.debug(depth, &block)
+ end
+
+ # Attempts to activate the current {#possibility}
+ # @return [void]
+ def attempt_to_activate
+ debug(depth) { 'Attempting to activate ' + possibility.to_s }
+ existing_vertex = activated.vertex_named(name)
+ if existing_vertex.payload
+ debug(depth) { "Found existing spec (#{existing_vertex.payload})" }
+ attempt_to_filter_existing_spec(existing_vertex)
+ else
+ latest = possibility.latest_version
+ possibility.possibilities.select! do |possibility|
+ requirement_satisfied_by?(requirement, activated, possibility)
+ end
+ if possibility.latest_version.nil?
+ # ensure there's a possibility for better error messages
+ possibility.possibilities << latest if latest
+ create_conflict
+ unwind_for_conflict
+ else
+ activate_new_spec
+ end
+ end
+ end
+
+ # Attempts to update the existing vertex's `PossibilitySet` with a filtered version
+ # @return [void]
+ def attempt_to_filter_existing_spec(vertex)
+ filtered_set = filtered_possibility_set(vertex)
+ if !filtered_set.possibilities.empty?
+ activated.set_payload(name, filtered_set)
+ new_requirements = requirements.dup
+ push_state_for_requirements(new_requirements, false)
+ else
+ create_conflict
+ debug(depth) { "Unsatisfied by existing spec (#{vertex.payload})" }
+ unwind_for_conflict
+ end
+ end
+
+ # Generates a filtered version of the existing vertex's `PossibilitySet` using the
+ # current state's `requirement`
+ # @param [Object] vertex existing vertex
+ # @return [PossibilitySet] filtered possibility set
+ def filtered_possibility_set(vertex)
+ PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities)
+ end
+
+ # @param [String] requirement_name the spec name to search for
+ # @return [Object] the locked spec named `requirement_name`, if one
+ # is found on {#base}
+ def locked_requirement_named(requirement_name)
+ vertex = base.vertex_named(requirement_name)
+ vertex && vertex.payload
+ end
+
+ # Add the current {#possibility} to the dependency graph of the current
+ # {#state}
+ # @return [void]
+ def activate_new_spec
+ conflicts.delete(name)
+ debug(depth) { "Activated #{name} at #{possibility}" }
+ activated.set_payload(name, possibility)
+ require_nested_dependencies_for(possibility)
+ end
+
+ # Requires the dependencies that the recently activated spec has
+ # @param [Object] possibility_set the PossibilitySet that has just been
+ # activated
+ # @return [void]
+ def require_nested_dependencies_for(possibility_set)
+ nested_dependencies = dependencies_for(possibility_set.latest_version)
+ debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" }
+ nested_dependencies.each do |d|
+ activated.add_child_vertex(name_for(d), nil, [name_for(possibility_set.latest_version)], d)
+ parent_index = states.size - 1
+ parents = @parents_of[d]
+ parents << parent_index if parents.empty?
+ end
+
+ push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?)
+ end
+
+ # Pushes a new {DependencyState} that encapsulates both existing and new
+ # requirements
+ # @param [Array] new_requirements
+ # @param [Boolean] requires_sort
+ # @param [Object] new_activated
+ # @return [void]
+ def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated)
+ new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort
+ new_requirement = nil
+ loop do
+ new_requirement = new_requirements.shift
+ break if new_requirement.nil? || states.none? { |s| s.requirement == new_requirement }
+ end
+ new_name = new_requirement ? name_for(new_requirement) : ''.freeze
+ possibilities = possibilities_for_requirement(new_requirement)
+ handle_missing_or_push_dependency_state DependencyState.new(
+ new_name, new_requirements, new_activated,
+ new_requirement, possibilities, depth, conflicts.dup, unused_unwind_options.dup
+ )
+ end
+
+ # Checks a proposed requirement with any existing locked requirement
+ # before generating an array of possibilities for it.
+ # @param [Object] requirement the proposed requirement
+ # @param [Object] activated
+ # @return [Array] possibilities
+ def possibilities_for_requirement(requirement, activated = self.activated)
+ return [] unless requirement
+ if locked_requirement_named(name_for(requirement))
+ return locked_requirement_possibility_set(requirement, activated)
+ end
+
+ group_possibilities(search_for(requirement))
+ end
+
+ # @param [Object] requirement the proposed requirement
+ # @param [Object] activated
+ # @return [Array] possibility set containing only the locked requirement, if any
+ def locked_requirement_possibility_set(requirement, activated = self.activated)
+ all_possibilities = search_for(requirement)
+ locked_requirement = locked_requirement_named(name_for(requirement))
+
+ # Longwinded way to build a possibilities array with either the locked
+ # requirement or nothing in it. Required, since the API for
+ # locked_requirement isn't guaranteed.
+ locked_possibilities = all_possibilities.select do |possibility|
+ requirement_satisfied_by?(locked_requirement, activated, possibility)
+ end
+
+ group_possibilities(locked_possibilities)
+ end
+
+ # Build an array of PossibilitySets, with each element representing a group of
+ # dependency versions that all have the same sub-dependency version constraints
+ # and are contiguous.
+ # @param [Array] possibilities an array of possibilities
+ # @return [Array<PossibilitySet>] an array of possibility sets
+ def group_possibilities(possibilities)
+ possibility_sets = []
+ current_possibility_set = nil
+
+ possibilities.reverse_each do |possibility|
+ dependencies = dependencies_for(possibility)
+ if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies)
+ current_possibility_set.possibilities.unshift(possibility)
+ else
+ possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility]))
+ current_possibility_set = possibility_sets.first
+ end
+ end
+
+ possibility_sets
+ end
+
+ # Pushes a new {DependencyState}.
+ # If the {#specification_provider} says to
+ # {SpecificationProvider#allow_missing?} that particular requirement, and
+ # there are no possibilities for that requirement, then `state` is not
+ # pushed, and the vertex in {#activated} is removed, and we continue
+ # resolving the remaining requirements.
+ # @param [DependencyState] state
+ # @return [void]
+ def handle_missing_or_push_dependency_state(state)
+ if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement)
+ state.activated.detach_vertex_named(state.name)
+ push_state_for_requirements(state.requirements.dup, false, state.activated)
+ else
+ states.push(state).tap { activated.tag(state) }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb
new file mode 100644
index 0000000000..d43121f8ca
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require_relative 'dependency_graph'
+
+module Gem::Resolver::Molinillo
+ # This class encapsulates a dependency resolver.
+ # The resolver is responsible for determining which set of dependencies to
+ # activate, with feedback from the {#specification_provider}
+ #
+ #
+ class Resolver
+ require_relative 'resolution'
+
+ # @return [SpecificationProvider] the specification provider used
+ # in the resolution process
+ attr_reader :specification_provider
+
+ # @return [UI] the UI module used to communicate back to the user
+ # during the resolution process
+ attr_reader :resolver_ui
+
+ # Initializes a new resolver.
+ # @param [SpecificationProvider] specification_provider
+ # see {#specification_provider}
+ # @param [UI] resolver_ui
+ # see {#resolver_ui}
+ def initialize(specification_provider, resolver_ui)
+ @specification_provider = specification_provider
+ @resolver_ui = resolver_ui
+ end
+
+ # Resolves the requested dependencies into a {DependencyGraph},
+ # locking to the base dependency graph (if specified)
+ # @param [Array] requested an array of 'requested' dependencies that the
+ # {#specification_provider} can understand
+ # @param [DependencyGraph,nil] base the base dependency graph to which
+ # dependencies should be 'locked'
+ def resolve(requested, base = DependencyGraph.new)
+ Resolution.new(specification_provider,
+ resolver_ui,
+ requested,
+ base).
+ resolve
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb
new file mode 100644
index 0000000000..6e7c715fce
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # A state that a {Resolution} can be in
+ # @attr [String] name the name of the current requirement
+ # @attr [Array<Object>] requirements currently unsatisfied requirements
+ # @attr [DependencyGraph] activated the graph of activated dependencies
+ # @attr [Object] requirement the current requirement
+ # @attr [Object] possibilities the possibilities to satisfy the current requirement
+ # @attr [Integer] depth the depth of the resolution
+ # @attr [Hash] conflicts unresolved conflicts, indexed by dependency name
+ # @attr [Array<UnwindDetails>] unused_unwind_options unwinds for previous conflicts that weren't explored
+ ResolutionState = Struct.new(
+ :name,
+ :requirements,
+ :activated,
+ :requirement,
+ :possibilities,
+ :depth,
+ :conflicts,
+ :unused_unwind_options
+ )
+
+ class ResolutionState
+ # Returns an empty resolution state
+ # @return [ResolutionState] an empty state
+ def self.empty
+ new(nil, [], DependencyGraph.new, nil, nil, 0, {}, [])
+ end
+ end
+
+ # A state that encapsulates a set of {#requirements} with an {Array} of
+ # possibilities
+ class DependencyState < ResolutionState
+ # Removes a possibility from `self`
+ # @return [PossibilityState] a state with a single possibility,
+ # the possibility that was removed from `self`
+ def pop_possibility_state
+ PossibilityState.new(
+ name,
+ requirements.dup,
+ activated,
+ requirement,
+ [possibilities.pop],
+ depth + 1,
+ conflicts.dup,
+ unused_unwind_options.dup
+ ).tap do |state|
+ state.activated.tag(state)
+ end
+ end
+ end
+
+ # A state that encapsulates a single possibility to fulfill the given
+ # {#requirement}
+ class PossibilityState < ResolutionState
+ end
+end
diff --git a/lib/rubygems/resolver/requirement_list.rb b/lib/rubygems/resolver/requirement_list.rb
index 6f86f0f412..5b51493c9a 100644
--- a/lib/rubygems/resolver/requirement_list.rb
+++ b/lib/rubygems/resolver/requirement_list.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The RequirementList is used to hold the requirements being considered
# while resolving a set of gems.
diff --git a/lib/rubygems/resolver/set.rb b/lib/rubygems/resolver/set.rb
index 243fee5fd5..5d8dd51eaa 100644
--- a/lib/rubygems/resolver/set.rb
+++ b/lib/rubygems/resolver/set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Resolver sets are used to look up specifications (and their
# dependencies) used in resolution. This set is abstract.
diff --git a/lib/rubygems/resolver/source_set.rb b/lib/rubygems/resolver/source_set.rb
index 296cf41078..bf8c23184e 100644
--- a/lib/rubygems/resolver/source_set.rb
+++ b/lib/rubygems/resolver/source_set.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
##
# The SourceSet chooses the best available method to query a remote index.
#
diff --git a/lib/rubygems/resolver/spec_specification.rb b/lib/rubygems/resolver/spec_specification.rb
index 00ef9fdba0..7b665fe876 100644
--- a/lib/rubygems/resolver/spec_specification.rb
+++ b/lib/rubygems/resolver/spec_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The Resolver::SpecSpecification contains common functionality for
# Resolver specifications that are backed by a Gem::Specification.
@@ -66,11 +65,4 @@ class Gem::Resolver::SpecSpecification < Gem::Resolver::Specification
def version
spec.version
end
-
- ##
- # The hash value for this specification.
-
- def hash
- spec.hash
- end
end
diff --git a/lib/rubygems/resolver/specification.rb b/lib/rubygems/resolver/specification.rb
index d2098ef0e2..3da803cab5 100644
--- a/lib/rubygems/resolver/specification.rb
+++ b/lib/rubygems/resolver/specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A Resolver::Specification contains a subset of the information
# contained in a Gem::Specification. Only the information necessary for
diff --git a/lib/rubygems/resolver/stats.rb b/lib/rubygems/resolver/stats.rb
index 9920976b2a..64b458f504 100644
--- a/lib/rubygems/resolver/stats.rb
+++ b/lib/rubygems/resolver/stats.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
class Gem::Resolver::Stats
def initialize
@max_depth = 0
@@ -33,7 +32,7 @@ class Gem::Resolver::Stats
@iterations += 1
end
- PATTERN = "%20s: %d\n"
+ PATTERN = "%20s: %d\n".freeze
def display
$stdout.puts "=== Resolver Statistics ==="
diff --git a/lib/rubygems/resolver/vendor_set.rb b/lib/rubygems/resolver/vendor_set.rb
index 293a1e3331..6c0ef2a1a1 100644
--- a/lib/rubygems/resolver/vendor_set.rb
+++ b/lib/rubygems/resolver/vendor_set.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A VendorSet represents gems that have been unpacked into a specific
# directory that contains a gemspec.
diff --git a/lib/rubygems/resolver/vendor_specification.rb b/lib/rubygems/resolver/vendor_specification.rb
index ac78f54558..600a98a2bf 100644
--- a/lib/rubygems/resolver/vendor_specification.rb
+++ b/lib/rubygems/resolver/vendor_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A VendorSpecification represents a gem that has been unpacked into a project
# and is being loaded through a gem dependencies file through the +path:+
diff --git a/lib/rubygems/s3_uri_signer.rb b/lib/rubygems/s3_uri_signer.rb
index 7c95a9d4f5..5522753af5 100644
--- a/lib/rubygems/s3_uri_signer.rb
+++ b/lib/rubygems/s3_uri_signer.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require_relative "openssl"
##
@@ -12,7 +10,7 @@ class Gem::S3URISigner
end
def to_s # :nodoc:
- super.to_s
+ "#{super}"
end
end
@@ -22,7 +20,7 @@ class Gem::S3URISigner
end
def to_s # :nodoc:
- super.to_s
+ "#{super}"
end
end
@@ -34,7 +32,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
@@ -49,7 +47,7 @@ class Gem::S3URISigner
string_to_sign = generate_string_to_sign(date_time, credential_info, canonical_request)
signature = generate_signature(s3_config, date, string_to_sign)
- Gem::URI.parse("https://#{canonical_host}#{uri.path}?#{query_params}&X-Amz-Signature=#{signature}")
+ URI.parse("https://#{canonical_host}#{uri.path}?#{query_params}&X-Amz-Signature=#{signature}")
end
private
@@ -136,11 +134,11 @@ 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
- require_relative "vendored_net_http"
+ require "net/http"
require_relative "request"
require_relative "request/connection_pools"
require "json"
@@ -152,13 +150,13 @@ class Gem::S3URISigner
end
def ec2_metadata_request(url)
- uri = Gem::URI(url)
+ uri = URI(url)
@request_pool ||= create_request_pool(uri)
- request = Gem::Request.new(uri, Gem::Net::HTTP::Get, nil, @request_pool)
+ request = Gem::Request.new(uri, Net::HTTP::Get, nil, @request_pool)
response = request.fetch
case response
- when Gem::Net::HTTPOK then
+ when Net::HTTPOK then
JSON.parse(response.body)
else
raise InstanceProfileError.new("Unable to fetch AWS metadata from #{uri}: #{response.message} #{response.code}")
@@ -172,6 +170,6 @@ class Gem::S3URISigner
end
BASE64_URI_TRANSLATE = { "+" => "%2B", "/" => "%2F", "=" => "%3D", "\n" => "" }.freeze
- EC2_IAM_INFO = "http://169.254.169.254/latest/meta-data/iam/info"
- EC2_IAM_SECURITY_CREDENTIALS = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
+ EC2_IAM_INFO = "http://169.254.169.254/latest/meta-data/iam/info".freeze
+ EC2_IAM_SECURITY_CREDENTIALS = "http://169.254.169.254/latest/meta-data/iam/security-credentials/".freeze
end
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 f8874b1b2f..0000000000
--- a/lib/rubygems/safe_marshal/elements.rb
+++ /dev/null
@@ -1,146 +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
-
- class UserClass < Element
- def initialize(name, wrapped_object)
- @name = name
- @wrapped_object = wrapped_object
- end
- attr_reader :name, :wrapped_object
- 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 740be113e5..0000000000
--- a/lib/rubygems/safe_marshal/reader.rb
+++ /dev/null
@@ -1,308 +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
- name = read_element
- wrapped_object = read_element
- Elements::UserClass.new(name, wrapped_object)
- 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 a9f1d048d4..0000000000
--- a/lib/rubygems/safe_marshal/visitors/to_ruby.rb
+++ /dev/null
@@ -1,415 +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 visit_Gem_SafeMarshal_Elements_UserClass(r)
- if resolve_class(r.name) == ::Hash && r.wrapped_object.is_a?(Elements::Hash)
-
- hash = register_object({}.compare_by_identity)
-
- o = r.wrapped_object
- o.pairs.each_with_index do |(k, v), i|
- push_stack i
- k = visit(k)
- push_stack k
- hash[k] = visit(v)
- end
-
- if o.is_a?(Elements::HashWithDefaultValue)
- push_stack :default
- hash.default = visit(o.default)
- end
-
- hash
- else
- raise UnsupportedError.new("Unsupported user class #{resolve_class(r.name)} in marshal stream", stack: formatted_stack)
- 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 UnsupportedError < Error
- def initialize(message, stack:)
- super "#{message} @ #{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 6a02a48230..5a98505598 100644
--- a/lib/rubygems/safe_yaml.rb
+++ b/lib/rubygems/safe_yaml.rb
@@ -1,6 +1,5 @@
-# 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,21 +24,34 @@ module Gem
runtime
].freeze
- @aliases_enabled = true
- def self.aliases_enabled=(value) # :nodoc:
- @aliases_enabled = !!value
- 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.aliases_enabled? # :nodoc:
- @aliases_enabled
- 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)
- ::Psych.safe_load(input, permitted_classes: PERMITTED_CLASSES, permitted_symbols: PERMITTED_SYMBOLS, aliases: @aliases_enabled)
- 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 69ba87b07f..3ba8c6957c 100644
--- a/lib/rubygems/security.rb
+++ b/lib/rubygems/security.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -323,9 +322,10 @@ require_relative "openssl"
# == Original author
#
# Paul Duncan <pabs@pablotron.org>
-# https://pablotron.org/
+# http://pablotron.org/
module Gem::Security
+
##
# Gem::Security default exception type
@@ -360,7 +360,7 @@ module Gem::Security
##
# One day in seconds
- ONE_DAY = 86_400
+ ONE_DAY = 86400
##
# One year in seconds
@@ -398,7 +398,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 +450,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 +461,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 +515,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 +528,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 +552,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 +601,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 +616,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 41f66043ad..d28005223e 100644
--- a/lib/rubygems/security/policies.rb
+++ b/lib/rubygems/security/policies.rb
@@ -1,17 +1,17 @@
# frozen_string_literal: true
-
module Gem::Security
+
##
# No security policy: all package signature checks are disabled.
NoSecurity = Policy.new(
"No Security",
- verify_data: false,
- verify_signer: false,
- verify_chain: false,
- verify_root: false,
- only_trusted: false,
- only_signed: false
+ :verify_data => false,
+ :verify_signer => false,
+ :verify_chain => false,
+ :verify_root => false,
+ :only_trusted => false,
+ :only_signed => false
)
##
@@ -24,12 +24,12 @@ module Gem::Security
AlmostNoSecurity = Policy.new(
"Almost No Security",
- verify_data: true,
- verify_signer: false,
- verify_chain: false,
- verify_root: false,
- only_trusted: false,
- only_signed: false
+ :verify_data => true,
+ :verify_signer => false,
+ :verify_chain => false,
+ :verify_root => false,
+ :only_trusted => false,
+ :only_signed => false
)
##
@@ -41,12 +41,12 @@ module Gem::Security
LowSecurity = Policy.new(
"Low Security",
- verify_data: true,
- verify_signer: true,
- verify_chain: false,
- verify_root: false,
- only_trusted: false,
- only_signed: false
+ :verify_data => true,
+ :verify_signer => true,
+ :verify_chain => false,
+ :verify_root => false,
+ :only_trusted => false,
+ :only_signed => false
)
##
@@ -60,12 +60,12 @@ module Gem::Security
MediumSecurity = Policy.new(
"Medium Security",
- verify_data: true,
- verify_signer: true,
- verify_chain: true,
- verify_root: true,
- only_trusted: true,
- only_signed: false
+ :verify_data => true,
+ :verify_signer => true,
+ :verify_chain => true,
+ :verify_root => true,
+ :only_trusted => true,
+ :only_signed => false
)
##
@@ -79,12 +79,12 @@ module Gem::Security
HighSecurity = Policy.new(
"High Security",
- verify_data: true,
- verify_signer: true,
- verify_chain: true,
- verify_root: true,
- only_trusted: true,
- only_signed: true
+ :verify_data => true,
+ :verify_signer => true,
+ :verify_chain => true,
+ :verify_root => true,
+ :only_trusted => true,
+ :only_signed => true
)
##
@@ -92,12 +92,12 @@ module Gem::Security
SigningPolicy = Policy.new(
"Signing Policy",
- verify_data: false,
- verify_signer: true,
- verify_chain: true,
- verify_root: true,
- only_trusted: false,
- only_signed: false
+ :verify_data => false,
+ :verify_signer => true,
+ :verify_chain => true,
+ :verify_root => true,
+ :only_trusted => false,
+ :only_signed => false
)
##
@@ -111,4 +111,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..959880ddc1 100644
--- a/lib/rubygems/security/policy.rb
+++ b/lib/rubygems/security/policy.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "../user_interaction"
##
@@ -135,7 +134,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 +170,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 +191,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 +205,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 +225,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 +287,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..cca82f1cf8 100644
--- a/lib/rubygems/security/signer.rb
+++ b/lib/rubygems/security/signer.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Basic OpenSSL-based package signing class.
@@ -106,7 +105,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 +174,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 d23d161cfe..df59680d84 100644
--- a/lib/rubygems/security/trust_dir.rb
+++ b/lib/rubygems/security/trust_dir.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The TrustDir manages the trusted certificates for gem signature
# verification.
@@ -9,8 +8,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 +44,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 +92,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,9 +110,9 @@ 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]
+ FileUtils.mkdir_p @dir, :mode => @permissions[:trust_dir]
end
end
end
diff --git a/lib/rubygems/security_option.rb b/lib/rubygems/security_option.rb
index 3a101fe9db..ab3898bf11 100644
--- a/lib/rubygems/security_option.rb
+++ b/lib/rubygems/security_option.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -29,7 +28,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/shellwords.rb b/lib/rubygems/shellwords.rb
deleted file mode 100644
index 741dccb363..0000000000
--- a/lib/rubygems/shellwords.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-autoload :Shellwords, "shellwords"
diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb
index bee5681dab..aa0cbc1641 100644
--- a/lib/rubygems/source.rb
+++ b/lib/rubygems/source.rb
@@ -12,9 +12,9 @@ class Gem::Source
include Gem::Text
FILES = { # :nodoc:
- released: "specs",
- latest: "latest_specs",
- prerelease: "prerelease_specs",
+ :released => "specs",
+ :latest => "latest_specs",
+ :prerelease => "prerelease_specs",
}.freeze
##
@@ -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
@@ -79,7 +81,7 @@ class Gem::Source
uri
end
- bundler_api_uri = enforce_trailing_slash(fetch_uri) + "versions"
+ bundler_api_uri = enforce_trailing_slash(fetch_uri)
begin
fetcher = Gem::RemoteFetcher.fetcher
@@ -100,7 +102,8 @@ 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)
end
@@ -134,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
@@ -157,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
##
@@ -189,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
@@ -213,16 +209,14 @@ class Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.group 2, "[Remote:", "]" do
- q.breakable
- q.text @uri.to_s
+ q.group 2, "[Remote:", "]" do
+ q.breakable
+ q.text @uri.to_s
- if api = uri
- q.breakable
- q.text "API URI: "
- q.text api.to_s
- end
+ if api = uri
+ q.breakable
+ q.text "API URI: "
+ q.text api.to_s
end
end
end
@@ -235,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 34f6851bc4..2609a309e8 100644
--- a/lib/rubygems/source/git.rb
+++ b/lib/rubygems/source/git.rb
@@ -53,7 +53,7 @@ class Gem::Source::Git < Gem::Source
@uri = Gem::Uri.parse(repository)
@name = name
@repository = repository
- @reference = reference || "HEAD"
+ @reference = reference
@need_submodules = submodules
@remote = true
@@ -70,6 +70,8 @@ class Gem::Source::Git < Gem::Source
-1
when Gem::Source then
1
+ else
+ nil
end
end
@@ -157,14 +159,12 @@ class Gem::Source::Git < Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.group 2, "[Git: ", "]" do
- q.breakable
- q.text @repository
+ q.group 2, "[Git: ", "]" do
+ q.breakable
+ q.text @repository
- q.breakable
- q.text @reference
- end
+ q.breakable
+ q.text @reference
end
end
@@ -223,14 +223,14 @@ class Gem::Source::Git < Gem::Source
end
##
- # A hash for the git gem based on the git repository Gem::URI.
+ # A hash for the git gem based on the git repository URI.
def uri_hash # :nodoc:
require_relative "../openssl"
normalized =
- if @repository.match?(%r{^\w+://(\w+@)?})
- uri = Gem::URI(@repository).normalize.to_s.sub %r{/$},""
+ if @repository =~ %r{^\w+://(\w+@)?}
+ uri = URI(@repository).normalize.to_s.sub %r{/$},""
uri.sub(/\A(\w+)/) { $1.downcase }
else
@repository
diff --git a/lib/rubygems/source/installed.rb b/lib/rubygems/source/installed.rb
index f5c96fee51..786faab3e3 100644
--- a/lib/rubygems/source/installed.rb
+++ b/lib/rubygems/source/installed.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Represents an installed gem. This is used for dependency resolution.
@@ -21,6 +20,8 @@ class Gem::Source::Installed < Gem::Source
0
when Gem::Source then
1
+ else
+ nil
end
end
@@ -32,8 +33,6 @@ class Gem::Source::Installed < Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.text "[Installed]"
- end
+ q.text "[Installed]"
end
end
diff --git a/lib/rubygems/source/local.rb b/lib/rubygems/source/local.rb
index ba6eea1f9a..ec1a594238 100644
--- a/lib/rubygems/source/local.rb
+++ b/lib/rubygems/source/local.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# The local source finds gems in the current directory for fulfilling
# dependencies.
@@ -24,12 +23,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 +40,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 +77,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 +113,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
@@ -117,14 +121,10 @@ class Gem::Source::Local < Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.group 2, "[Local gems:", "]" do
- q.breakable
- if @specs
- q.seplist @specs.keys do |v|
- q.text v.full_name
- end
- end
+ q.group 2, "[Local gems:", "]" do
+ q.breakable
+ q.seplist @specs.keys do |v|
+ q.text v.full_name
end
end
end
diff --git a/lib/rubygems/source/lock.rb b/lib/rubygems/source/lock.rb
index 70849210bd..49f097467b 100644
--- a/lib/rubygems/source/lock.rb
+++ b/lib/rubygems/source/lock.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A Lock source wraps an installed gem's source and sorts before other sources
# during dependency resolution. This allows RubyGems to prefer gems from
@@ -25,11 +24,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 dde1d48a21..552aeba50f 100644
--- a/lib/rubygems/source/specific_file.rb
+++ b/lib/rubygems/source/specific_file.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# A source representing a single .gem file. This is used for installation of
# local gems.
@@ -34,6 +33,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:
@@ -42,11 +42,9 @@ class Gem::Source::SpecificFile < Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.group 2, "[SpecificFile:", "]" do
- q.breakable
- q.text @path
- end
+ q.group 2, "[SpecificFile:", "]" do
+ q.breakable
+ q.text @path
end
end
diff --git a/lib/rubygems/source/vendor.rb b/lib/rubygems/source/vendor.rb
index 44ef614441..543acf1388 100644
--- a/lib/rubygems/source/vendor.rb
+++ b/lib/rubygems/source/vendor.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# This represents a vendored source that is similar to an installed gem.
@@ -19,6 +18,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 33db64fbc1..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:
@@ -44,15 +44,15 @@ class Gem::SourceList
end
##
- # Appends +obj+ to the source list which may be a Gem::Source, Gem::URI or URI
+ # Appends +obj+ to the source list which may be a Gem::Source, URI or URI
# String.
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 9c0399f196..0d06d1f144 100644
--- a/lib/rubygems/spec_fetcher.rb
+++ b/lib/rubygems/spec_fetcher.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
require_relative "remote_fetcher"
require_relative "user_interaction"
require_relative "errors"
@@ -69,9 +68,9 @@ class Gem::SpecFetcher
@prerelease_specs = {}
@caches = {
- latest: @latest_specs,
- prerelease: @prerelease_specs,
- released: @specs,
+ :latest => @latest_specs,
+ :prerelease => @prerelease_specs,
+ :released => @specs,
}
@fetcher = Gem::RemoteFetcher.fetcher
@@ -92,9 +91,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 +123,7 @@ class Gem::SpecFetcher
tuples = tuples.sort_by {|x| x[0].version }
- [tuples, errors]
+ return [tuples, errors]
end
##
@@ -155,14 +154,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
##
@@ -176,19 +177,26 @@ class Gem::SpecFetcher
matches = names.map do |n|
next unless n.match_platform?
- distance = levenshtein_distance gem_name, n.name.downcase.tr("_-", "")
- next if distance >= max
- return [n.name] if distance == 0
- [n.name, distance]
+ [n.name, 0] if n.name.downcase.tr("_-", "").include?(gem_name)
end.compact
+ if matches.length < num_results
+ matches += names.map do |n|
+ next unless n.match_platform?
+ distance = levenshtein_distance gem_name, n.name.downcase.tr("_-", "")
+ next if distance >= max
+ return [n.name] if distance == 0
+ [n.name, distance]
+ end.compact
+ end
+
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
##
@@ -206,32 +214,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]
@@ -243,7 +253,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 e438669945..5175db2d84 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
@@ -11,11 +10,8 @@ require_relative "deprecate"
require_relative "basic_specification"
require_relative "stub_specification"
require_relative "platform"
-require_relative "specification_record"
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:
@@ -109,7 +105,7 @@ class Gem::Specification < Gem::BasicSpecification
@load_cache = {} # :nodoc:
@load_cache_mutex = Thread::Mutex.new
- VALID_NAME_PATTERN = /\A[a-zA-Z0-9\.\-\_]+\z/ # :nodoc:
+ VALID_NAME_PATTERN = /\A[a-zA-Z0-9\.\-\_]+\z/.freeze # :nodoc:
# :startdoc:
@@ -128,35 +124,35 @@ class Gem::Specification < Gem::BasicSpecification
# Map of attribute names to default values.
@@default_value = {
- authors: [],
- autorequire: nil,
- bindir: "bin",
- cert_chain: [],
- date: nil,
- dependencies: [],
- description: nil,
- email: nil,
- executables: [],
- extensions: [],
- extra_rdoc_files: [],
- files: [],
- homepage: nil,
- licenses: [],
- metadata: {},
- name: nil,
- platform: Gem::Platform::RUBY,
- post_install_message: nil,
- rdoc_options: [],
- require_paths: ["lib"],
- required_ruby_version: Gem::Requirement.default,
- required_rubygems_version: Gem::Requirement.default,
- requirements: [],
- rubygems_version: Gem::VERSION,
- signing_key: nil,
- specification_version: CURRENT_SPECIFICATION_VERSION,
- summary: nil,
- test_files: [],
- version: nil,
+ :authors => [],
+ :autorequire => nil,
+ :bindir => "bin",
+ :cert_chain => [],
+ :date => nil,
+ :dependencies => [],
+ :description => nil,
+ :email => nil,
+ :executables => [],
+ :extensions => [],
+ :extra_rdoc_files => [],
+ :files => [],
+ :homepage => nil,
+ :licenses => [],
+ :metadata => {},
+ :name => nil,
+ :platform => Gem::Platform::RUBY,
+ :post_install_message => nil,
+ :rdoc_options => [],
+ :require_paths => ["lib"],
+ :required_ruby_version => Gem::Requirement.default,
+ :required_rubygems_version => Gem::Requirement.default,
+ :requirements => [],
+ :rubygems_version => Gem::VERSION,
+ :signing_key => nil,
+ :specification_version => CURRENT_SPECIFICATION_VERSION,
+ :summary => nil,
+ :test_files => [],
+ :version => nil,
}.freeze
# rubocop:disable Style/MutableConstant
@@ -165,27 +161,39 @@ 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.select {|_k,v| v.is_a?(Array) }.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
+ def self.clear_specs # :nodoc:
+ @@all = nil
+ @@stubs = nil
+ @@stubs_by_name = {}
+ @@spec_with_requirable_file = {}
+ @@active_stub_with_requirable_file = {}
+ end
+ private_class_method :clear_specs
+
+ clear_specs
+
# Sentinel object to represent "not found" stubs
NOT_FOUND = Struct.new(:to_spec, :this).new # :nodoc:
- deprecate_constant :NOT_FOUND
# Tracking removed method calls to warn users during build time.
- REMOVED_METHODS = [:rubyforge_project=, :mark_version].freeze # :nodoc:
+ REMOVED_METHODS = [:rubyforge_project=].freeze # :nodoc:
def removed_method_calls
@removed_method_calls ||= []
end
@@ -254,7 +262,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
##
@@ -292,7 +301,7 @@ class Gem::Specification < Gem::BasicSpecification
#
# Usage:
#
- # spec.description = <<~EOF
+ # spec.description = <<-EOF
# Rake is a Make-like program implemented in Ruby. Tasks and
# dependencies are specified in standard Ruby syntax.
# EOF
@@ -329,10 +338,10 @@ class Gem::Specification < Gem::BasicSpecification
# The simplest way is to specify the standard SPDX ID
# https://spdx.org/licenses/ for the license.
# Ideally, you should pick one that is OSI (Open Source Initiative)
- # https://opensource.org/licenses/ approved.
+ # http://opensource.org/licenses/alphabetical approved.
#
# The most commonly used OSI-approved licenses are MIT and Apache-2.0.
- # GitHub also provides a license picker at https://choosealicense.com/.
+ # GitHub also provides a license picker at http://choosealicense.com/.
#
# You can also use a custom license file along with your gemspec and specify
# a LicenseRef-<idstring>, where idstring is the name of the file containing
@@ -417,11 +426,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
@@ -493,6 +502,8 @@ class Gem::Specification < Gem::BasicSpecification
@platform = @new_platform.to_s
invalidate_memoized_attributes
+
+ @new_platform
end
##
@@ -522,6 +533,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
@@ -546,9 +564,9 @@ class Gem::Specification < Gem::BasicSpecification
#
# Usage:
#
- # spec.add_dependency 'example', '~> 1.1', '>= 1.1.4'
+ # spec.add_runtime_dependency 'example', '~> 1.1', '>= 1.1.4'
- def add_dependency(gem, *requirements)
+ def add_runtime_dependency(gem, *requirements)
if requirements.uniq.size != requirements.size
warn "WARNING: duplicated #{gem} dependency #{requirements}"
end
@@ -559,7 +577,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.
@@ -580,7 +598,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:
#
@@ -709,21 +727,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
##
@@ -731,7 +734,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.
@@ -761,7 +764,7 @@ class Gem::Specification < Gem::BasicSpecification
attr_accessor :specification_version
def self._all # :nodoc:
- specification_record.all
+ @@all ||= Gem.loaded_specs.values | stubs.map(&:to_spec)
end
def self.clear_load_cache # :nodoc:
@@ -771,22 +774,34 @@ class Gem::Specification < Gem::BasicSpecification
end
private_class_method :clear_load_cache
- def self.gem_path # :nodoc:
- Gem.path
- end
- private_class_method :gem_path
-
def self.each_gemspec(dirs) # :nodoc:
dirs.each do |dir|
Gem::Util.glob_files_in_dir("*.gemspec", dir).each do |path|
- yield path
+ yield path.tap(&Gem::UNTAINT)
end
end
end
- def self.gemspec_stubs_in(dir, pattern) # :nodoc:
+ def self.gemspec_stubs_in(dir, pattern)
Gem::Util.glob_files_in_dir(pattern, dir).map {|path| yield path }.select(&:valid?)
end
+ private_class_method :gemspec_stubs_in
+
+ def self.installed_stubs(dirs, pattern)
+ map_stubs(dirs, pattern) do |path, base_dir, gems_dir|
+ Gem::StubSpecification.gemspec_stub(path, base_dir, gems_dir)
+ end
+ end
+ private_class_method :installed_stubs
+
+ def self.map_stubs(dirs, pattern) # :nodoc:
+ dirs.flat_map do |dir|
+ base_dir = File.dirname dir
+ gems_dir = File.join base_dir, "gems"
+ gemspec_stubs_in(dir, pattern) {|path| yield path, base_dir, gems_dir }
+ end
+ end
+ private_class_method :map_stubs
def self.each_spec(dirs) # :nodoc:
each_gemspec(dirs) do |path|
@@ -799,7 +814,13 @@ class Gem::Specification < Gem::BasicSpecification
# Returns a Gem::StubSpecification for every installed gem
def self.stubs
- specification_record.stubs
+ @@stubs ||= begin
+ pattern = "*.gemspec"
+ stubs = stubs_for_pattern(pattern, false)
+
+ @@stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name)
+ stubs
+ end
end
##
@@ -818,7 +839,13 @@ class Gem::Specification < Gem::BasicSpecification
# only returns stubs that match Gem.platforms
def self.stubs_for(name)
- specification_record.stubs_for(name)
+ if @@stubs
+ @@stubs_by_name[name] || []
+ else
+ @@stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s|
+ s.name == name
+ end
+ end
end
##
@@ -826,7 +853,12 @@ class Gem::Specification < Gem::BasicSpecification
# optionally filtering out specs not matching the current platform
#
def self.stubs_for_pattern(pattern, match_platform = true) # :nodoc:
- specification_record.stubs_for_pattern(pattern, match_platform)
+ 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 {|stub| stub.full_name }
+ _resort!(stubs)
+ stubs
end
def self._resort!(specs) # :nodoc:
@@ -835,11 +867,7 @@ class Gem::Specification < Gem::BasicSpecification
next names if names.nonzero?
versions = b.version <=> a.version
next versions if versions.nonzero?
- platforms = Gem::Platform.sort_priority(b.platform) <=> Gem::Platform.sort_priority(a.platform)
- next platforms if platforms.nonzero?
- default_gem = a.default_gem_priority <=> b.default_gem_priority
- next default_gem if default_gem.nonzero?
- a.base_dir_priority(gem_path) <=> b.base_dir_priority(gem_path)
+ Gem::Platform.sort_priority(b.platform)
end
end
@@ -859,14 +887,23 @@ class Gem::Specification < Gem::BasicSpecification
# properly sorted.
def self.add_spec(spec)
- specification_record.add_spec(spec)
+ return if _all.include? spec
+
+ _all << spec
+ stubs << spec
+ (@@stubs_by_name[spec.name] ||= []) << spec
+
+ _resort!(@@stubs_by_name[spec.name])
+ _resort!(stubs)
end
##
# Removes +spec+ from the known specs.
def self.remove_spec(spec)
- specification_record.remove_spec(spec)
+ _all.delete spec.to_spec
+ stubs.delete spec
+ (@@stubs_by_name[spec.name] || []).delete spec
end
##
@@ -874,23 +911,33 @@ class Gem::Specification < Gem::BasicSpecification
# You probably want to use one of the Enumerable methods instead.
def self.all
- warn "NOTE: Specification.all called from #{caller(1, 1).first}" unless
+ warn "NOTE: Specification.all called from #{caller.first}" unless
Gem::Deprecate.skip
_all
end
##
- # Sets the known specs to +specs+.
+ # Sets the known specs to +specs+. Not guaranteed to work for you in
+ # the future. Use at your own risk. Caveat emptor. Doomy doom doom.
+ # Etc etc.
+ #
+ #--
+ # Makes +specs+ the known specs
+ # Listen, time is a river
+ # Winter comes, code breaks
+ #
+ # -- wilsonb
def self.all=(specs)
- specification_record.all = specs
+ @@stubs_by_name = specs.group_by(&:name)
+ @@all = @@stubs = specs
end
##
# Return full names of all specs in sorted order.
def self.all_names
- specification_record.all_names
+ self._all.map(&:full_name)
end
##
@@ -915,7 +962,9 @@ class Gem::Specification < Gem::BasicSpecification
# Return the directories that Specification uses to find specs.
def self.dirs
- @@dirs ||= Gem::SpecificationRecord.dirs_from(gem_path)
+ @@dirs ||= Gem.path.collect do |dir|
+ File.join dir.dup.tap(&Gem::UNTAINT), "specifications"
+ end
end
##
@@ -923,9 +972,9 @@ class Gem::Specification < Gem::BasicSpecification
# this resets the list of known specs.
def self.dirs=(dirs)
- reset
+ self.reset
- @@dirs = Gem::SpecificationRecord.dirs_from(Array(dirs))
+ @@dirs = Array(dirs).map {|dir| File.join dir, "specifications" }
end
extend Enumerable
@@ -934,15 +983,23 @@ class Gem::Specification < Gem::BasicSpecification
# Enumerate every known spec. See ::dirs= and ::add_spec to set the list of
# specs.
- def self.each(&block)
- specification_record.each(&block)
+ def self.each
+ return enum_for(:each) unless block_given?
+
+ self._all.each do |x|
+ yield x
+ end
end
##
# Returns every spec that matches +name+ and optional +requirements+.
def self.find_all_by_name(name, *requirements)
- specification_record.find_all_by_name(name, *requirements)
+ requirements = Gem::Requirement.default if requirements.empty?
+
+ # TODO: maybe try: find_all { |s| spec === dep }
+
+ Gem::Dependency.new(name, *requirements).matching_specs
end
##
@@ -959,20 +1016,20 @@ class Gem::Specification < Gem::BasicSpecification
def self.find_by_name(name, *requirements)
requirements = Gem::Requirement.default if requirements.empty?
- Gem::Dependency.new(name, *requirements).to_spec
- end
+ # TODO: maybe try: find { |s| spec === dep }
- ##
- # Find the best specification matching a +full_name+.
- def self.find_by_full_name(full_name)
- stubs.find {|s| s.full_name == full_name }&.to_spec
+ Gem::Dependency.new(name, *requirements).to_spec
end
##
# Return the best specification that contains the file matching +path+.
def self.find_by_path(path)
- specification_record.find_by_path(path)
+ path = path.dup.freeze
+ spec = @@spec_with_requirable_file[path] ||= (stubs.find do |s|
+ s.contains_requirable_file? path
+ end || NOT_FOUND)
+ spec.to_spec
end
##
@@ -980,15 +1037,18 @@ class Gem::Specification < Gem::BasicSpecification
# amongst the specs that are not activated.
def self.find_inactive_by_path(path)
- specification_record.find_inactive_by_path(path)
+ stub = stubs.find do |s|
+ next if s.activated?
+ s.contains_requirable_file? path
+ end
+ stub && stub.to_spec
end
- ##
- # Return the best specification that contains the file matching +path+, among
- # those already activated.
-
def self.find_active_stub_by_path(path)
- specification_record.find_active_stub_by_path(path)
+ stub = @@active_stub_with_requirable_file[path] ||= (stubs.find do |s|
+ s.activated? && s.contains_requirable_file?(path)
+ end || NOT_FOUND)
+ stub.this
end
##
@@ -1004,7 +1064,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
@@ -1017,7 +1077,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
@@ -1055,28 +1115,26 @@ class Gem::Specification < Gem::BasicSpecification
# +prerelease+ is true.
def self.latest_specs(prerelease = false)
- specification_record.latest_specs(prerelease)
+ _latest_specs Gem::Specification.stubs, prerelease
end
##
# Return the latest installed spec for gem +name+.
def self.latest_spec_for(name)
- specification_record.latest_spec_for(name)
+ latest_specs(true).find {|installed_spec| installed_spec.name == name }
end
def self._latest_specs(specs, prerelease = false) # :nodoc:
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
##
@@ -1085,33 +1143,36 @@ 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)
code = Gem.open_file(file, "r:UTF-8:-", &:read)
+ 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
@@ -1199,8 +1260,8 @@ class Gem::Specification < Gem::BasicSpecification
def self.reset
@@dirs = nil
- Gem.pre_reset_hooks.each(&:call)
- @specification_record = nil
+ Gem.pre_reset_hooks.each {|hook| hook.call }
+ clear_specs
clear_load_cache
unresolved = unresolved_deps
unless unresolved.empty?
@@ -1208,7 +1269,7 @@ class Gem::Specification < Gem::BasicSpecification
unresolved.values.each do |dep|
warn " #{dep}"
- versions = find_all_by_name(dep.name).uniq(&:full_name)
+ versions = find_all_by_name(dep.name)
unless versions.empty?
warn " Available/installed versions of this gem:"
versions.each {|s| warn " - #{s.version}" }
@@ -1218,14 +1279,7 @@ class Gem::Specification < Gem::BasicSpecification
warn "Please report a bug if this causes problems."
unresolved.clear
end
- Gem.post_reset_hooks.each(&:call)
- end
-
- ##
- # Keeps track of all currently known specifications
-
- def self.specification_record
- @specification_record ||= Gem::SpecificationRecord.new(dirs)
+ Gem.post_reset_hooks.each {|hook| hook.call }
end
# DOC: This method needs documented or nodoc'd
@@ -1238,23 +1292,10 @@ 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
@@ -1264,23 +1305,17 @@ class Gem::Specification < Gem::BasicSpecification
message = e.message
raise unless message.include?("YAML::")
- unless Object.const_defined?(:YAML)
- Object.const_set "YAML", Psych
- yaml_set = true
- end
+ Object.const_set "YAML", Psych unless Object.const_defined?(:YAML)
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
end
spec = Gem::Specification.new
@@ -1318,7 +1353,7 @@ class Gem::Specification < Gem::BasicSpecification
spec.instance_variable_set :@has_rdoc, array[15]
spec.instance_variable_set :@new_platform, array[16]
spec.instance_variable_set :@platform, array[16].to_s
- spec.instance_variable_set :@licenses, [array[17]]
+ spec.instance_variable_set :@license, array[17]
spec.instance_variable_set :@metadata, array[18]
spec.instance_variable_set :@loaded, false
spec.instance_variable_set :@activated, false
@@ -1374,7 +1409,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
@@ -1385,11 +1420,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
##
@@ -1400,7 +1435,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
@@ -1412,9 +1447,9 @@ class Gem::Specification < Gem::BasicSpecification
end
begin
- specs = spec_dep.to_specs.uniq(&:full_name)
+ 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
@@ -1460,7 +1495,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
@@ -1478,8 +1513,8 @@ class Gem::Specification < Gem::BasicSpecification
else
executables
end
- rescue StandardError
- nil
+ rescue
+ return nil
end
##
@@ -1504,7 +1539,7 @@ class Gem::Specification < Gem::BasicSpecification
private :add_dependency_with_type
- alias_method :add_runtime_dependency, :add_dependency
+ alias add_dependency add_runtime_dependency
##
# Adds this spec's require paths to LOAD_PATH, in the proper location.
@@ -1556,7 +1591,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
@@ -1571,11 +1606,9 @@ class Gem::Specification < Gem::BasicSpecification
def build_extensions # :nodoc:
return if extensions.empty?
return if default_gem?
- # 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
@@ -1593,7 +1626,7 @@ class Gem::Specification < Gem::BasicSpecification
builder.build_extensions
end
ensure
- ui&.close
+ ui.close if ui
Gem::Specification.unresolved_deps.replace unresolved_deps
end
end
@@ -1633,7 +1666,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
@@ -1649,7 +1682,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
@@ -1659,12 +1692,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.
@@ -1688,7 +1723,7 @@ class Gem::Specification < Gem::BasicSpecification
/\A
(\d{4})-(\d{2})-(\d{2})
(\s+ \d{2}:\d{2}:\d{2}\.\d+ \s* (Z | [-+]\d\d:\d\d) )?
- \Z/x
+ \Z/x.freeze
##
# The date this gem was created
@@ -1700,17 +1735,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
@@ -1760,12 +1795,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
@@ -1775,7 +1811,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
##
@@ -1811,15 +1847,17 @@ class Gem::Specification < Gem::BasicSpecification
end
def encode_with(coder) # :nodoc:
+ mark_version
+
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
@@ -1942,7 +1980,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?
##
@@ -1953,7 +1991,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:
@@ -2010,8 +2048,7 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # Duplicates Array and Gem::Requirement attributes from +other_spec+ so state isn't shared.
- #
+ # Duplicates array_attributes from +other_spec+ so state isn't shared.
def initialize_copy(other_spec)
self.class.array_attributes.each do |name|
@@ -2033,9 +2070,6 @@ class Gem::Specification < Gem::BasicSpecification
raise e
end
end
-
- @required_ruby_version = other_spec.required_ruby_version.dup
- @required_rubygems_version = other_spec.required_rubygems_version.dup
end
def base_dir
@@ -2105,6 +2139,13 @@ class Gem::Specification < Gem::BasicSpecification
end
##
+ # Sets the rubygems_version to the current RubyGems version.
+
+ def mark_version
+ @rubygems_version = Gem::VERSION
+ end
+
+ ##
# Track removed method calls to warn about during build time.
# Warn about unknown attributes while loading a spec.
@@ -2184,7 +2225,7 @@ class Gem::Specification < Gem::BasicSpecification
# The platform this gem runs on. See Gem::Platform for details.
def platform
- @new_platform ||= Gem::Platform::RUBY # rubocop:disable Naming/MemoizedInstanceVariableName
+ @new_platform ||= Gem::Platform::RUBY
end
def pretty_print(q) # :nodoc:
@@ -2197,22 +2238,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
@@ -2222,7 +2264,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.
@@ -2230,7 +2272,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
@@ -2295,13 +2337,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)})"
@@ -2322,7 +2364,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?
@@ -2331,8 +2373,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
##
@@ -2421,6 +2463,7 @@ class Gem::Specification < Gem::BasicSpecification
# still have their default values are omitted.
def to_ruby
+ mark_version
result = []
result << "# -*- encoding: utf-8 -*-"
result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{raw_require_paths.join("\0")}"
@@ -2458,19 +2501,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}"
+ result << " s.installed_by_version = \"#{Gem::VERSION}\" if s.respond_to? :installed_by_version"
end
unless dependencies.empty?
@@ -2479,8 +2522,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
@@ -2541,9 +2585,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
@@ -2551,10 +2596,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
@@ -2585,10 +2631,6 @@ class Gem::Specification < Gem::BasicSpecification
@test_files.delete_if {|x| File.directory?(x) && !File.symlink?(x) }
end
- def validate_for_resolution
- Gem::SpecificationPolicy.new(self).validate_for_resolution
- end
-
def validate_metadata
Gem::SpecificationPolicy.new(self).validate_metadata
end
@@ -2605,13 +2647,22 @@ class Gem::Specification < Gem::BasicSpecification
rubygems_deprecate :validate_permissions
##
- # Set the version to +version+.
+ # Set the version to +version+, potentially also setting
+ # required_rubygems_version if +version+ indicates it is a
+ # prerelease.
def version=(version)
@version = Gem::Version.create(version)
return if @version.nil?
+ # skip to set required_ruby_version when pre-released rubygems.
+ # It caused to raise CircularDependencyError
+ if @version.prerelease? && (@name.nil? || @name.strip != "rubygems")
+ self.required_rubygems_version = "> 1.3.1"
+ end
invalidate_memoized_attributes
+
+ return @version
end
def stubbed?
@@ -2623,9 +2674,9 @@ class Gem::Specification < Gem::BasicSpecification
case ivar
when "date"
# Force Date to go through the extra coerce logic in date=
- self.date = val
+ self.date = val.tap(&Gem::UNTAINT)
else
- instance_variable_set "@#{ivar}", val
+ instance_variable_set "@#{ivar}", val.tap(&Gem::UNTAINT)
end
end
@@ -2642,19 +2693,17 @@ 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
end
@installed_by_version ||= nil
-
- nil
end
def flatten_require_paths # :nodoc:
diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb
index d79ee7df92..6f4d79cdcf 100644
--- a/lib/rubygems/specification_policy.rb
+++ b/lib/rubygems/specification_policy.rb
@@ -1,25 +1,22 @@
-# frozen_string_literal: true
-
require_relative "user_interaction"
class Gem::SpecificationPolicy
include Gem::UserInteraction
- VALID_NAME_PATTERN = /\A[a-zA-Z0-9\.\-\_]+\z/ # :nodoc:
+ VALID_NAME_PATTERN = /\A[a-zA-Z0-9\.\-\_]+\z/.freeze # :nodoc:
- SPECIAL_CHARACTERS = /\A[#{Regexp.escape(".-_")}]+/ # :nodoc:
+ SPECIAL_CHARACTERS = /\A[#{Regexp.escape('.-_')}]+/.freeze # :nodoc:
- VALID_URI_PATTERN = %r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z} # :nodoc:
+ VALID_URI_PATTERN = %r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z}.freeze # :nodoc:
METADATA_LINK_KEYS = %w[
- homepage_uri
+ bug_tracker_uri
changelog_uri
- source_code_uri
documentation_uri
- wiki_uri
+ homepage_uri
mailing_list_uri
- bug_tracker_uri
- download_uri
+ source_code_uri
+ wiki_uri
funding_uri
].freeze # :nodoc:
@@ -45,7 +42,6 @@ class Gem::SpecificationPolicy
def validate(strict = false)
validate_required!
- validate_required_metadata!
validate_optional(strict) if packaging || strict
@@ -86,15 +82,13 @@ class Gem::SpecificationPolicy
validate_authors_field
- validate_licenses_length
-
- validate_duplicate_dependencies
- end
-
- def validate_required_metadata!
validate_metadata
+ validate_licenses_length
+
validate_lazy_metadata
+
+ validate_duplicate_dependencies
end
def validate_optional(strict)
@@ -106,14 +100,10 @@ class Gem::SpecificationPolicy
validate_dependencies
- validate_required_ruby_version
-
validate_extensions
validate_removed_attributes
- validate_unique_links
-
if @warnings > 0
if strict
error "specification has warnings"
@@ -124,13 +114,6 @@ class Gem::SpecificationPolicy
end
##
- # Implementation for Specification#validate_for_resolution
-
- def validate_for_resolution
- validate_required!
- end
-
- ##
# Implementation for Specification#validate_metadata
def validate_metadata
@@ -142,7 +125,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
@@ -150,7 +133,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
@@ -158,9 +141,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
@@ -177,7 +161,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
@@ -189,7 +173,6 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
end
##
- # Checks that the gem does not depend on itself.
# Checks that dependencies use requirements as we recommend. Warnings are
# issued when dependencies are open-ended or overly strict for semantic
# versioning.
@@ -197,10 +180,6 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
def validate_dependencies # :nodoc:
warning_messages = []
@specification.dependencies.each do |dep|
- if dep.name == @specification.name # warn on self reference
- warning_messages << "Self referencing dependency is unnecessary and strongly discouraged."
- end
-
prerelease_dep = dep.requirements_list.any? do |req|
Gem::Requirement.new(req).prerelease?
end
@@ -209,42 +188,37 @@ 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 }
end
end
- def validate_required_ruby_version
- if @specification.required_ruby_version.requirements == [Gem::Requirement::DefaultRequirement]
- warning "make sure you specify the oldest ruby version constraint (like \">= 3.0\") that you want your gem to support by setting the `required_ruby_version` gemspec attribute"
- end
- end
-
##
# Issues a warning for each file to be packaged which is world-readable.
#
@@ -255,7 +229,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
@@ -274,7 +248,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
@@ -284,9 +258,7 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
return if rubygems_version == Gem::VERSION
- warning "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}"
-
- @specification.rubygems_version = Gem::VERSION
+ error "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}"
end
def validate_required_attributes
@@ -302,12 +274,12 @@ 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)
- error "invalid value for attribute name: #{name.dump} cannot begin with a period, dash, or underscore"
+ elsif name =~ SPECIAL_CHARACTERS
+ error "invalid value for attribute name: #{name.dump} can not begin with a period, dash, or underscore"
end
end
@@ -360,13 +332,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
@@ -381,8 +353,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
@@ -393,38 +363,26 @@ 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
LAZY = '"FIxxxXME" or "TOxxxDO"'.gsub(/xxx/, "")
- LAZY_PATTERN = /\AFI XME|\ATO DO/x
- HOMEPAGE_URI_PATTERN = /\A[a-z][a-z\d+.-]*:/i
+ LAZY_PATTERN = /\AFI XME|\ATO DO/x.freeze
+ HOMEPAGE_URI_PATTERN = /\A[a-z][a-z\d+.-]*:/i.freeze
def validate_lazy_metadata
unless @specification.authors.grep(LAZY_PATTERN).empty?
@@ -435,11 +393,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
@@ -447,13 +405,13 @@ or set it to nil if you don't want to specify a license.
# Make sure a homepage is valid HTTP/HTTPS URI
if homepage && !homepage.empty?
- require_relative "vendor/uri/lib/uri"
+ require "uri"
begin
- homepage_uri = Gem::URI.parse(homepage)
- unless [Gem::URI::HTTP, Gem::URI::HTTPS].member? homepage_uri.class
+ homepage_uri = URI.parse(homepage)
+ unless [URI::HTTP, URI::HTTPS].member? homepage_uri.class
error "\"#{homepage}\" is not a valid HTTP URI"
end
- rescue Gem::URI::InvalidURIError
+ rescue URI::InvalidURIError
error "\"#{homepage}\" is not a valid HTTP URI"
end
end
@@ -517,29 +475,13 @@ You have specified rust based extension, but Cargo.lock is not part of the gem f
def validate_rake_extensions(builder) # :nodoc:
rake_extension = @specification.extensions.any? {|s| builder.builder_for(s) == Gem::Ext::RakeBuilder }
- rake_dependency = @specification.dependencies.any? {|d| d.name == "rake" && d.type == :runtime }
+ rake_dependency = @specification.dependencies.any? {|d| d.name == "rake" }
warning <<-WARNING if rake_extension && !rake_dependency
-You have specified rake based extension, but rake is not added as runtime dependency. It is recommended to add rake as a runtime dependency in gemspec since there's no guarantee rake will be already installed.
+You have specified rake based extension, but rake is not added as dependency. It is recommended to add rake as a dependency in gemspec since there's no guarantee rake will be already installed.
WARNING
end
- def validate_unique_links
- links = @specification.metadata.slice(*METADATA_LINK_KEYS)
- grouped = links.group_by {|_key, uri| uri }
- grouped.each do |uri, copies|
- next unless copies.length > 1
- keys = copies.map(&:first).join("\n ")
- warning <<~WARNING
- You have specified the uri:
- #{uri}
- for all of the following keys:
- #{keys}
- Only the first one will be shown on rubygems.org
- WARNING
- end
- end
-
def warning(statement) # :nodoc:
@warnings += 1
diff --git a/lib/rubygems/specification_record.rb b/lib/rubygems/specification_record.rb
deleted file mode 100644
index 195a355496..0000000000
--- a/lib/rubygems/specification_record.rb
+++ /dev/null
@@ -1,212 +0,0 @@
-# frozen_string_literal: true
-
-module Gem
- class SpecificationRecord
- def self.dirs_from(paths)
- paths.map do |path|
- File.join(path, "specifications")
- end
- end
-
- def self.from_path(path)
- new(dirs_from([path]))
- end
-
- def initialize(dirs)
- @all = nil
- @stubs = nil
- @stubs_by_name = {}
- @spec_with_requirable_file = {}
- @active_stub_with_requirable_file = {}
-
- @dirs = dirs
- end
-
- # Sentinel object to represent "not found" stubs
- NOT_FOUND = Struct.new(:to_spec, :this).new
- private_constant :NOT_FOUND
-
- ##
- # Returns the list of all specifications in the record
-
- def all
- @all ||= stubs.map(&:to_spec)
- end
-
- ##
- # Returns a Gem::StubSpecification for every specification in the record
-
- def stubs
- @stubs ||= begin
- pattern = "*.gemspec"
- stubs = stubs_for_pattern(pattern, false)
-
- @stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name)
- stubs
- end
- end
-
- ##
- # Returns a Gem::StubSpecification for every specification in the record
- # named +name+ only returns stubs that match Gem.platforms
-
- def stubs_for(name)
- if @stubs
- @stubs_by_name[name] || []
- else
- @stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s|
- s.name == name
- end
- end
- end
-
- ##
- # Finds stub specifications matching a pattern in the record, optionally
- # filtering out specs not matching the current platform
-
- def stubs_for_pattern(pattern, match_platform = true)
- installed_stubs = installed_stubs(pattern)
- installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
- stubs = installed_stubs + Gem::Specification.default_stubs(pattern)
- Gem::Specification._resort!(stubs)
- stubs
- end
-
- ##
- # Adds +spec+ to the the record, keeping the collection properly sorted.
-
- def add_spec(spec)
- return if all.include? spec
-
- all << spec
- stubs << spec
- (@stubs_by_name[spec.name] ||= []) << spec
-
- Gem::Specification._resort!(@stubs_by_name[spec.name])
- Gem::Specification._resort!(stubs)
- end
-
- ##
- # Removes +spec+ from the record.
-
- def remove_spec(spec)
- all.delete spec.to_spec
- stubs.delete spec
- (@stubs_by_name[spec.name] || []).delete spec
- end
-
- ##
- # Sets the specs known by the record to +specs+.
-
- def all=(specs)
- @stubs_by_name = specs.group_by(&:name)
- @all = @stubs = specs
- end
-
- ##
- # Return full names of all specs in the record in sorted order.
-
- def all_names
- all.map(&:full_name)
- end
-
- include Enumerable
-
- ##
- # Enumerate every known spec.
-
- def each
- return enum_for(:each) unless block_given?
-
- all.each do |x|
- yield x
- end
- end
-
- ##
- # Returns every spec in the record that matches +name+ and optional +requirements+.
-
- def find_all_by_name(name, *requirements)
- req = Gem::Requirement.create(*requirements)
- env_req = Gem.env_requirement(name)
-
- matches = stubs_for(name).find_all do |spec|
- req.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
- end.map(&:to_spec)
-
- if name == "bundler" && !req.specific?
- require_relative "bundler_version_finder"
- Gem::BundlerVersionFinder.prioritize!(matches)
- end
-
- matches
- end
-
- ##
- # Return the best specification in the record that contains the file matching +path+.
-
- def find_by_path(path)
- path = path.dup.freeze
- spec = @spec_with_requirable_file[path] ||= stubs.find do |s|
- s.contains_requirable_file? path
- end || NOT_FOUND
-
- spec.to_spec
- end
-
- ##
- # Return the best specification in the record that contains the file
- # matching +path+ amongst the specs that are not activated.
-
- def find_inactive_by_path(path)
- stub = stubs.find do |s|
- next if s.activated?
- s.contains_requirable_file? path
- end
- stub&.to_spec
- end
-
- ##
- # Return the best specification in the record that contains the file
- # matching +path+, among those already activated.
-
- def find_active_stub_by_path(path)
- stub = @active_stub_with_requirable_file[path] ||= stubs.find do |s|
- s.activated? && s.contains_requirable_file?(path)
- end || NOT_FOUND
-
- stub.this
- end
-
- ##
- # Return the latest specs in the record, optionally including prerelease
- # specs if +prerelease+ is true.
-
- def latest_specs(prerelease)
- Gem::Specification._latest_specs stubs, prerelease
- end
-
- ##
- # Return the latest installed spec in the record for gem +name+.
-
- def latest_spec_for(name)
- latest_specs(true).find {|installed_spec| installed_spec.name == name }
- end
-
- private
-
- def installed_stubs(pattern)
- map_stubs(pattern) do |path, base_dir, gems_dir|
- Gem::StubSpecification.gemspec_stub(path, base_dir, gems_dir)
- end
- end
-
- def map_stubs(pattern)
- @dirs.flat_map do |dir|
- base_dir = File.dirname dir
- gems_dir = File.join base_dir, "gems"
- Gem::Specification.gemspec_stubs_in(dir, pattern) {|path| yield path, base_dir, gems_dir }
- end
- end
- end
-end
diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb
index 4f6a70ba4b..512ca9143d 100644
--- a/lib/rubygems/stub_specification.rb
+++ b/lib/rubygems/stub_specification.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
##
# Gem::StubSpecification reads the stub: line from the gemspec. This prevents
# us having to eval the entire gemspec in order to find out certain
@@ -7,10 +6,10 @@
class Gem::StubSpecification < Gem::BasicSpecification
# :nodoc:
- PREFIX = "# stub: "
+ PREFIX = "# stub: ".freeze
# :nodoc:
- OPEN_MODE = "r:UTF-8:-"
+ OPEN_MODE = "r:UTF-8:-".freeze
class StubLine # :nodoc: all
attr_reader :name, :version, :platform, :require_paths, :extensions,
@@ -20,9 +19,9 @@ class Gem::StubSpecification < Gem::BasicSpecification
# These are common require paths.
REQUIRE_PATHS = { # :nodoc:
- "lib" => "lib",
- "test" => "test",
- "ext" => "ext",
+ "lib" => "lib".freeze,
+ "test" => "test".freeze,
+ "ext" => "ext".freeze,
}.freeze
# These are common require path lists. This hash is used to optimize
@@ -34,8 +33,8 @@ class Gem::StubSpecification < Gem::BasicSpecification
}.freeze
def initialize(data, extensions)
- parts = data[PREFIX.length..-1].split(" ", 4)
- @name = -parts[0]
+ parts = data[PREFIX.length..-1].split(" ".freeze, 4)
+ @name = parts[0].freeze
@version = if Gem::Version.correct?(parts[1])
Gem::Version.new(parts[1])
else
@@ -51,7 +50,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
end
path_list = parts.last
- @require_paths = REQUIRE_PATH_LIST[path_list] || path_list.split("\0").map! do |x|
+ @require_paths = REQUIRE_PATH_LIST[path_list] || path_list.split("\0".freeze).map! do |x|
REQUIRE_PATHS[x] || x
end
end
@@ -69,6 +68,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
def initialize(filename, base_dir, gems_dir, default_gem)
super()
+ filename.tap(&Gem::UNTAINT)
self.loaded_from = filename
@data = nil
@@ -83,7 +83,11 @@ class Gem::StubSpecification < Gem::BasicSpecification
# True when this gem has been activated
def activated?
- @activated ||= !loaded_spec.nil?
+ @activated ||=
+ begin
+ loaded = Gem.loaded_specs[name]
+ loaded && loaded.version == version
+ end
end
def default_gem?
@@ -107,23 +111,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
@@ -182,11 +183,14 @@ class Gem::StubSpecification < Gem::BasicSpecification
##
# The full Gem::Specification for this gem, loaded from evalling its gemspec
- def spec
- @spec ||= loaded_spec if @data
+ def to_spec
+ @spec ||= if @data
+ loaded = Gem.loaded_specs[name]
+ loaded if loaded && loaded.version == version
+ end
+
@spec ||= Gem::Specification.load(loaded_from)
end
- alias_method :to_spec, :spec
##
# Is this StubSpecification valid? i.e. have we found a stub line, OR does
@@ -202,34 +206,4 @@ class Gem::StubSpecification < Gem::BasicSpecification
def stubbed?
data.is_a? StubLine
end
-
- def ==(other) # :nodoc:
- self.class === other &&
- name == other.name &&
- version == other.version &&
- platform == other.platform
- end
-
- alias_method :eql?, :== # :nodoc:
-
- def hash # :nodoc:
- name.hash ^ version.hash ^ platform.hash
- end
-
- def <=>(other) # :nodoc:
- sort_obj <=> other.sort_obj
- end
-
- def sort_obj # :nodoc:
- [name, version, Gem::Platform.sort_priority(platform)]
- end
-
- private
-
- def loaded_spec
- spec = Gem.loaded_specs[name]
- return unless spec && spec.version == version && spec.default_gem? == default_gem?
-
- spec
- end
end
diff --git a/lib/rubygems/text.rb b/lib/rubygems/text.rb
index da0795b771..d6b891380e 100644
--- a/lib/rubygems/text.rb
+++ b/lib/rubygems/text.rb
@@ -4,11 +4,12 @@
# A collection of text-wrangling methods
module Gem::Text
+
##
# Remove any non-printable characters and make the text suitable for
# printing.
def clean_text(text)
- text.gsub(/[\000-\b\v-\f\016-\037\177]/, ".")
+ text.gsub(/[\000-\b\v-\f\016-\037\177]/, ".".freeze)
end
def truncate_text(text, description, max_length = 100_000)
@@ -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/tsort.rb b/lib/rubygems/tsort.rb
new file mode 100644
index 0000000000..60ebe22e81
--- /dev/null
+++ b/lib/rubygems/tsort.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require_relative "tsort/lib/tsort"
diff --git a/lib/bundler/vendor/fileutils/.document b/lib/rubygems/tsort/.document
index 0c43bbd6b3..0c43bbd6b3 100644
--- a/lib/bundler/vendor/fileutils/.document
+++ b/lib/rubygems/tsort/.document
diff --git a/lib/rubygems/tsort/lib/tsort.rb b/lib/rubygems/tsort/lib/tsort.rb
new file mode 100644
index 0000000000..f825f14257
--- /dev/null
+++ b/lib/rubygems/tsort/lib/tsort.rb
@@ -0,0 +1,452 @@
+# frozen_string_literal: true
+
+#--
+# tsort.rb - provides a module for topological sorting and strongly connected components.
+#++
+#
+
+#
+# Gem::TSort implements topological sorting using Tarjan's algorithm for
+# strongly connected components.
+#
+# Gem::TSort is designed to be able to be used with any object which can be
+# interpreted as a directed graph.
+#
+# Gem::TSort requires two methods to interpret an object as a graph,
+# tsort_each_node and tsort_each_child.
+#
+# * tsort_each_node is used to iterate for all nodes over a graph.
+# * tsort_each_child is used to iterate for child nodes of a given node.
+#
+# The equality of nodes are defined by eql? and hash since
+# Gem::TSort uses Hash internally.
+#
+# == A Simple Example
+#
+# The following example demonstrates how to mix the Gem::TSort module into an
+# existing class (in this case, Hash). Here, we're treating each key in
+# the hash as a node in the graph, and so we simply alias the required
+# #tsort_each_node method to Hash's #each_key method. For each key in the
+# hash, the associated value is an array of the node's child nodes. This
+# choice in turn leads to our implementation of the required #tsort_each_child
+# method, which fetches the array of child nodes and then iterates over that
+# array using the user-supplied block.
+#
+# require 'rubygems/tsort/lib/tsort'
+#
+# class Hash
+# include Gem::TSort
+# alias tsort_each_node each_key
+# def tsort_each_child(node, &block)
+# fetch(node).each(&block)
+# end
+# end
+#
+# {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort
+# #=> [3, 2, 1, 4]
+#
+# {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components
+# #=> [[4], [2, 3], [1]]
+#
+# == A More Realistic Example
+#
+# A very simple `make' like tool can be implemented as follows:
+#
+# require 'rubygems/tsort/lib/tsort'
+#
+# class Make
+# def initialize
+# @dep = {}
+# @dep.default = []
+# end
+#
+# def rule(outputs, inputs=[], &block)
+# triple = [outputs, inputs, block]
+# outputs.each {|f| @dep[f] = [triple]}
+# @dep[triple] = inputs
+# end
+#
+# def build(target)
+# each_strongly_connected_component_from(target) {|ns|
+# if ns.length != 1
+# fs = ns.delete_if {|n| Array === n}
+# raise Gem::TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
+# end
+# n = ns.first
+# if Array === n
+# outputs, inputs, block = n
+# inputs_time = inputs.map {|f| File.mtime f}.max
+# begin
+# outputs_time = outputs.map {|f| File.mtime f}.min
+# rescue Errno::ENOENT
+# outputs_time = nil
+# end
+# if outputs_time == nil ||
+# inputs_time != nil && outputs_time <= inputs_time
+# sleep 1 if inputs_time != nil && inputs_time.to_i == Time.now.to_i
+# block.call
+# end
+# end
+# }
+# end
+#
+# def tsort_each_child(node, &block)
+# @dep[node].each(&block)
+# end
+# include Gem::TSort
+# end
+#
+# def command(arg)
+# print arg, "\n"
+# system arg
+# end
+#
+# m = Make.new
+# m.rule(%w[t1]) { command 'date > t1' }
+# m.rule(%w[t2]) { command 'date > t2' }
+# m.rule(%w[t3]) { command 'date > t3' }
+# m.rule(%w[t4], %w[t1 t3]) { command 'cat t1 t3 > t4' }
+# m.rule(%w[t5], %w[t4 t2]) { command 'cat t4 t2 > t5' }
+# m.build('t5')
+#
+# == Bugs
+#
+# * 'tsort.rb' is wrong name because this library uses
+# Tarjan's algorithm for strongly connected components.
+# Although 'strongly_connected_components.rb' is correct but too long.
+#
+# == References
+#
+# R. E. Tarjan, "Depth First Search and Linear Graph Algorithms",
+# <em>SIAM Journal on Computing</em>, Vol. 1, No. 2, pp. 146-160, June 1972.
+#
+
+module Gem::TSort
+ class Cyclic < StandardError
+ end
+
+ # Returns a topologically sorted array of nodes.
+ # The array is sorted from children to parents, i.e.
+ # the first element has no child and the last node has no parent.
+ #
+ # If there is a cycle, Gem::TSort::Cyclic is raised.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # p graph.tsort #=> [4, 2, 3, 1]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # p graph.tsort # raises Gem::TSort::Cyclic
+ #
+ def tsort
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Gem::TSort.tsort(each_node, each_child)
+ end
+
+ # Returns a topologically sorted array of nodes.
+ # The array is sorted from children to parents, i.e.
+ # the first element has no child and the last node has no parent.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # If there is a cycle, Gem::TSort::Cyclic is raised.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Gem::TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
+ #
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Gem::TSort.tsort(each_node, each_child) # raises Gem::TSort::Cyclic
+ #
+ def self.tsort(each_node, each_child)
+ tsort_each(each_node, each_child).to_a
+ end
+
+ # The iterator version of the #tsort method.
+ # <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
+ # modification of _obj_ during the iteration may lead to unexpected results.
+ #
+ # #tsort_each returns +nil+.
+ # If there is a cycle, Gem::TSort::Cyclic is raised.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # graph.tsort_each {|n| p n }
+ # #=> 4
+ # # 2
+ # # 3
+ # # 1
+ #
+ def tsort_each(&block) # :yields: node
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Gem::TSort.tsort_each(each_node, each_child, &block)
+ end
+
+ # The iterator version of the Gem::TSort.tsort method.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # Gem::TSort.tsort_each(each_node, each_child) {|n| p n }
+ # #=> 4
+ # # 2
+ # # 3
+ # # 1
+ #
+ def self.tsort_each(each_node, each_child) # :yields: node
+ return to_enum(__method__, each_node, each_child) unless block_given?
+
+ each_strongly_connected_component(each_node, each_child) {|component|
+ if component.size == 1
+ yield component.first
+ else
+ raise Cyclic.new("topological sort failed: #{component.inspect}")
+ end
+ }
+ end
+
+ # Returns strongly connected components as an array of arrays of nodes.
+ # The array is sorted from children to parents.
+ # Each elements of the array represents a strongly connected component.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
+ #
+ def strongly_connected_components
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Gem::TSort.strongly_connected_components(each_node, each_child)
+ end
+
+ # Returns strongly connected components as an array of arrays of nodes.
+ # The array is sorted from children to parents.
+ # Each elements of the array represents a strongly connected component.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Gem::TSort.strongly_connected_components(each_node, each_child)
+ # #=> [[4], [2], [3], [1]]
+ #
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Gem::TSort.strongly_connected_components(each_node, each_child)
+ # #=> [[4], [2, 3], [1]]
+ #
+ def self.strongly_connected_components(each_node, each_child)
+ each_strongly_connected_component(each_node, each_child).to_a
+ end
+
+ # The iterator version of the #strongly_connected_components method.
+ # <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
+ # <tt><em>obj</em>.strongly_connected_components.each</tt>, but
+ # modification of _obj_ during the iteration may lead to unexpected results.
+ #
+ # #each_strongly_connected_component returns +nil+.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # graph.each_strongly_connected_component {|scc| p scc }
+ # #=> [4]
+ # # [2]
+ # # [3]
+ # # [1]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # graph.each_strongly_connected_component {|scc| p scc }
+ # #=> [4]
+ # # [2, 3]
+ # # [1]
+ #
+ def each_strongly_connected_component(&block) # :yields: nodes
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Gem::TSort.each_strongly_connected_component(each_node, each_child, &block)
+ end
+
+ # The iterator version of the Gem::TSort.strongly_connected_components method.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
+ # #=> [4]
+ # # [2]
+ # # [3]
+ # # [1]
+ #
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
+ # #=> [4]
+ # # [2, 3]
+ # # [1]
+ #
+ def self.each_strongly_connected_component(each_node, each_child) # :yields: nodes
+ return to_enum(__method__, each_node, each_child) unless block_given?
+
+ id_map = {}
+ stack = []
+ each_node.call {|node|
+ unless id_map.include? node
+ each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
+ yield c
+ }
+ end
+ }
+ nil
+ end
+
+ # Iterates over strongly connected component in the subgraph reachable from
+ # _node_.
+ #
+ # Return value is unspecified.
+ #
+ # #each_strongly_connected_component_from doesn't call #tsort_each_node.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # graph.each_strongly_connected_component_from(2) {|scc| p scc }
+ # #=> [4]
+ # # [2]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # graph.each_strongly_connected_component_from(2) {|scc| p scc }
+ # #=> [4]
+ # # [2, 3]
+ #
+ def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
+ Gem::TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
+ end
+
+ # Iterates over strongly connected components in a graph.
+ # The graph is represented by _node_ and _each_child_.
+ #
+ # _node_ is the first node.
+ # _each_child_ should have +call+ method which takes a node argument
+ # and yields for each child node.
+ #
+ # Return value is unspecified.
+ #
+ # #Gem::TSort.each_strongly_connected_component_from is a class method and
+ # it doesn't need a class to represent a graph which includes Gem::TSort.
+ #
+ # graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_child = lambda {|n, &b| graph[n].each(&b) }
+ # Gem::TSort.each_strongly_connected_component_from(1, each_child) {|scc|
+ # p scc
+ # }
+ # #=> [4]
+ # # [2, 3]
+ # # [1]
+ #
+ def self.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
+ return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
+
+ minimum_id = node_id = id_map[node] = id_map.size
+ stack_length = stack.length
+ stack << node
+
+ each_child.call(node) {|child|
+ if id_map.include? child
+ child_id = id_map[child]
+ minimum_id = child_id if child_id && child_id < minimum_id
+ else
+ sub_minimum_id =
+ each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
+ yield c
+ }
+ minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
+ end
+ }
+
+ if node_id == minimum_id
+ component = stack.slice!(stack_length .. -1)
+ component.each {|n| id_map[n] = nil}
+ yield component
+ end
+
+ minimum_id
+ end
+
+ # Should be implemented by a extended class.
+ #
+ # #tsort_each_node is used to iterate for all nodes over a graph.
+ #
+ def tsort_each_node # :yields: node
+ raise NotImplementedError.new
+ end
+
+ # Should be implemented by a extended class.
+ #
+ # #tsort_each_child is used to iterate for child nodes of _node_.
+ #
+ def tsort_each_child(node) # :yields: child
+ raise NotImplementedError.new
+ end
+end
diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb
index 471c29b6e4..5883ed1c41 100644
--- a/lib/rubygems/uninstaller.rb
+++ b/lib/rubygems/uninstaller.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -32,7 +31,7 @@ class Gem::Uninstaller
attr_reader :bin_dir
##
- # The gem repository the gem will be uninstalled from
+ # The gem repository the gem will be installed into
attr_reader :gem_home
@@ -46,12 +45,11 @@ 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
- @install_dir = options[:install_dir]
- @gem_home = File.realpath(@install_dir || Gem.dir)
- @user_dir = File.exist?(Gem.user_dir) ? File.realpath(Gem.user_dir) : Gem.user_dir
+ @gem_home = File.realpath(options[:install_dir] || Gem.dir)
+ @plugins_dir = Gem.plugindir(@gem_home)
@force_executables = options[:executables]
@force_all = options[:all]
@force_ignore = options[:ignore]
@@ -71,7 +69,7 @@ class Gem::Uninstaller
# only add user directory if install_dir is not set
@user_install = false
- @user_install = options[:user_install] unless @install_dir
+ @user_install = options[:user_install] unless options[:install_dir]
# Optimization: populated during #uninstall
@default_specs_matching_uninstall_params = []
@@ -86,7 +84,11 @@ class Gem::Uninstaller
list = []
- specification_record.stubs.each do |spec|
+ dirs =
+ Gem::Specification.dirs +
+ [Gem.default_specifications_dir]
+
+ Gem::Specification.each_spec dirs do |spec|
next unless dependency.matches_spec? spec
list << spec
@@ -96,13 +98,15 @@ 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.map(&:to_spec)
+ @default_specs_matching_uninstall_params = default_specs
list, other_repo_specs = list.partition do |spec|
@gem_home == spec.base_dir ||
- (@user_install && spec.base_dir == @user_dir)
+ (@user_install && spec.base_dir == Gem.user_dir)
end
list.sort!
@@ -110,7 +114,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|
@@ -122,7 +126,7 @@ class Gem::Uninstaller
remove_all list
elsif list.size > 1
- gem_names = list.map(&:full_name_with_location)
+ gem_names = list.map {|gem| gem.full_name }
gem_names << "All versions"
say
@@ -130,7 +134,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}]"
@@ -143,9 +147,7 @@ class Gem::Uninstaller
##
# Uninstalls gem +spec+
- def uninstall_gem(stub)
- spec = stub.to_spec
-
+ def uninstall_gem(spec)
@spec = spec
unless dependencies_ok? spec
@@ -163,8 +165,6 @@ class Gem::Uninstaller
remove_plugins @spec
remove @spec
- specification_record.remove_spec(stub)
-
regenerate_plugins
Gem.post_uninstall_hooks.each do |hook|
@@ -178,7 +178,7 @@ class Gem::Uninstaller
# Removes installed executables and batch files (windows only) for +spec+.
def remove_executables(spec)
- return if spec.executables.empty? || default_spec_matches?(spec)
+ return if spec.executables.empty?
executables = spec.executables.clone
@@ -200,8 +200,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
@@ -240,9 +240,9 @@ class Gem::Uninstaller
def remove(spec)
unless path_ok?(@gem_home, spec) ||
- (@user_install && path_ok?(@user_dir, 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
@@ -251,15 +251,7 @@ class Gem::Uninstaller
raise Gem::FilePermissionError, spec.base_dir unless
File.writable?(spec.base_dir)
- full_gem_path = spec.full_gem_path
- exclusions = []
-
- if default_spec_matches?(spec) && spec.executables.any?
- exclusions = spec.executables.map {|exe| File.join(spec.bin_dir, exe) }
- exclusions << File.dirname(exclusions.last) until exclusions.last == full_gem_path
- end
-
- safe_delete { rm_r full_gem_path, exclusions: exclusions }
+ safe_delete { FileUtils.rm_r spec.full_gem_path }
safe_delete { FileUtils.rm_r spec.extension_dir }
old_platform_name = spec.original_name
@@ -283,6 +275,8 @@ class Gem::Uninstaller
safe_delete { FileUtils.rm_r gemspec }
announce_deletion_of(spec)
+
+ Gem::Specification.reset
end
##
@@ -291,17 +285,17 @@ class Gem::Uninstaller
def remove_plugins(spec) # :nodoc:
return if spec.plugins.empty?
- remove_plugins_for(spec, plugin_dir_for(spec))
+ remove_plugins_for(spec, @plugins_dir)
end
##
# Regenerates plugin wrappers after removal.
def regenerate_plugins
- latest = specification_record.latest_spec_for(@spec.name)
+ latest = Gem::Specification.latest_spec_for(@spec.name)
return if latest.nil?
- regenerate_plugins_for(latest, plugin_dir_for(@spec))
+ regenerate_plugins_for(latest, @plugins_dir)
end
##
@@ -347,7 +341,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
@@ -355,7 +349,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
##
@@ -386,16 +380,6 @@ class Gem::Uninstaller
private
- def rm_r(path, exclusions:)
- FileUtils::Entry_.new(path).postorder_traverse do |ent|
- ent.remove unless exclusions.include?(ent.path)
- end
- end
-
- def specification_record
- @specification_record ||= @install_dir ? Gem::SpecificationRecord.from_path(@install_dir) : Gem::Specification.specification_record
- end
-
def announce_deletion_of(spec)
name = spec.full_name
say "Successfully uninstalled #{name}"
@@ -423,8 +407,4 @@ class Gem::Uninstaller
say "Gem #{spec.full_name} cannot be uninstalled because it is a default gem"
end
end
-
- def plugin_dir_for(spec)
- Gem.plugindir(spec.base_dir)
- end
end
diff --git a/lib/rubygems/update_suggestion.rb b/lib/rubygems/update_suggestion.rb
index 6f3ec5f493..c2e81b2374 100644
--- a/lib/rubygems/update_suggestion.rb
+++ b/lib/rubygems/update_suggestion.rb
@@ -4,6 +4,15 @@
# Mixin methods for Gem::Command to promote available RubyGems update
module Gem::UpdateSuggestion
+ # list taken from https://github.com/watson/ci-info/blob/7a3c30d/index.js#L56-L66
+ CI_ENV_VARS = [
+ "CI", # Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari
+ "CONTINUOUS_INTEGRATION", # Travis CI, Cirrus CI
+ "BUILD_NUMBER", # Jenkins, TeamCity
+ "CI_APP_ID", "CI_BUILD_ID", "CI_BUILD_NUMBER", # Applfow
+ "RUN_ID" # TaskCluster, dsari
+ ].freeze
+
ONE_WEEK = 7 * 24 * 60 * 60
##
@@ -19,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"]
@@ -30,7 +39,7 @@ Run `gem update --system #{Gem.latest_rubygems_version}` to update your installa
return false unless Gem.ui.tty?
return false if Gem.rubygems_version.prerelease?
return false if Gem.disable_system_update_message
- return false if Gem::CIDetector.ci?
+ return false if ci?
# check makes sense only when we can store timestamp of last try
# otherwise we will not be able to prevent "annoying" update message
@@ -44,13 +53,17 @@ 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
+
+ def ci?
+ CI_ENV_VARS.any? {|var| ENV.include?(var) }
+ end
end
diff --git a/lib/rubygems/uri.rb b/lib/rubygems/uri.rb
index a44aaceba5..4b5d035aa0 100644
--- a/lib/rubygems/uri.rb
+++ b/lib/rubygems/uri.rb
@@ -16,9 +16,9 @@ class Gem::Uri
# Parses uri, raising if it's invalid
def self.parse!(uri)
- require_relative "vendor/uri/lib/uri"
+ require "uri"
- raise Gem::URI::InvalidURIError unless uri
+ raise URI::InvalidURIError unless uri
return uri unless uri.is_a?(String)
@@ -28,9 +28,9 @@ class Gem::Uri
# as "%7BDESede%7D". If this is escaped again the percentage
# symbols will be escaped.
begin
- Gem::URI.parse(uri)
- rescue Gem::URI::InvalidURIError
- Gem::URI.parse(Gem::URI::DEFAULT_PARSER.escape(uri))
+ URI.parse(uri)
+ rescue URI::InvalidURIError
+ URI.parse(URI::DEFAULT_PARSER.escape(uri))
end
end
@@ -39,7 +39,7 @@ class Gem::Uri
def self.parse(uri)
parse!(uri)
- rescue Gem::URI::InvalidURIError
+ rescue URI::InvalidURIError
uri
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 0172c4ee89..2fa505423b 100644
--- a/lib/rubygems/user_interaction.rb
+++ b/lib/rubygems/user_interaction.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -14,6 +13,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 +68,7 @@ module Gem::DefaultUserInteraction
def use_ui(new_ui, &block)
Gem::DefaultUserInteraction.use_ui(new_ui, &block)
end
+
end
##
@@ -90,6 +91,7 @@ end
# end
module Gem::UserInteraction
+
include Gem::DefaultUserInteraction
##
@@ -193,7 +195,7 @@ class Gem::StreamUI
# then special operations (like asking for passwords) will use the TTY
# commands to disable character echo.
- def initialize(in_stream, out_stream, err_stream=$stderr, usetty=true)
+ def initialize(in_stream, out_stream, err_stream=STDERR, usetty=true)
@ins = in_stream
@outs = out_stream
@errs = err_stream
@@ -237,8 +239,7 @@ class Gem::StreamUI
return nil, nil unless result
result = result.strip.to_i - 1
- return nil, nil unless (0...list.size) === result
- [list[result], result]
+ return list[result], result
end
##
@@ -257,38 +258,39 @@ 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
result = @ins.gets
- result&.chomp!
+ result.chomp! if result
result
end
@@ -296,14 +298,14 @@ 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
password = _gets_noecho
@outs.puts
- password&.chomp!
+ password.chomp! if password
password
end
@@ -426,7 +428,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 +471,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
@@ -591,8 +595,8 @@ class Gem::StreamUI
end
##
-# Subclass of StreamUI that instantiates the user interaction using $stdin,
-# $stdout, and $stderr.
+# Subclass of StreamUI that instantiates the user interaction using STDIN,
+# STDOUT, and STDERR.
class Gem::ConsoleUI < Gem::StreamUI
##
@@ -600,7 +604,7 @@ class Gem::ConsoleUI < Gem::StreamUI
# stdin, output to stdout and warnings or errors to stderr.
def initialize
- super $stdin, $stdout, $stderr, true
+ super STDIN, STDOUT, STDERR, true
end
end
diff --git a/lib/rubygems/util.rb b/lib/rubygems/util.rb
index 51f9c2029f..05e5788932 100644
--- a/lib/rubygems/util.rb
+++ b/lib/rubygems/util.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-
require_relative "deprecate"
##
# This module contains various utility methods as module methods.
module Gem::Util
+
##
# Zlib::GzipReader wrapper that unzips +data+.
@@ -60,7 +60,7 @@ module Gem::Util
# Invokes system, but silences all output.
def self.silent_system(*command)
- opt = { out: IO::NULL, err: [:child, :out] }
+ opt = { :out => IO::NULL, :err => [:child, :out] }
if Hash === command.last
opt.update(command.last)
cmds = command[0...-1]
@@ -84,11 +84,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
@@ -105,14 +101,15 @@ module Gem::Util
end
##
- # Corrects +path+ (usually returned by `Gem::URI.parse().path` on Windows), that
+ # Corrects +path+ (usually returned by `URI.parse().path` on Windows), that
# comes with a leading slash.
def self.correct_for_windows_path(path)
- if path[0].chr == "/" && path[1].chr.match?(/[a-z]/i) && path[2].chr == ":"
+ if path[0].chr == "/" && path[1].chr =~ /[a-z]/i && path[2].chr == ":"
path[1..-1]
else
path
end
end
+
end
diff --git a/lib/rubygems/util/licenses.rb b/lib/rubygems/util/licenses.rb
index 192ae30b9b..96f47781c0 100644
--- a/lib/rubygems/util/licenses.rb
+++ b/lib/rubygems/util/licenses.rb
@@ -1,21 +1,16 @@
# 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
extend Gem::Text
- NONSTANDARD = "Nonstandard"
- LICENSE_REF = "LicenseRef-.+"
+ NONSTANDARD = "Nonstandard".freeze
+ LICENSE_REF = "LicenseRef-.+".freeze
# Software Package Data Exchange (SPDX) standard open-source software
# license identifiers
LICENSE_IDENTIFIERS = %w[
0BSD
- 3D-Slicer-1.0
AAL
ADSL
AFL-1.1
@@ -23,14 +18,14 @@ 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
- AMD-newlib
AMDPLPA
AML
- AML-glslang
AMPAS
ANTLR-PD
ANTLR-PD-fallback
@@ -40,35 +35,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-Display-PostScript
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-Darwin
+ BSD-2-Clause-FreeBSD
+ BSD-2-Clause-NetBSD
BSD-2-Clause-Patent
BSD-2-Clause-Views
- BSD-2-Clause-first-lines
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
@@ -76,37 +63,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-acpica
- 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-Source-beginning-file
- BSD-Systemics
- BSD-Systemics-W3Works
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-2-Clause
- Brian-Gladman-3-Clause
C-UDA-1.0
CAL-1.0
CAL-1.0-Combined-Work-Exception
@@ -114,43 +84,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-AU
- 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
@@ -159,8 +116,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
@@ -168,7 +123,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
@@ -181,36 +135,22 @@ class Gem::Licenses
CERN-OHL-P-2.0
CERN-OHL-S-2.0
CERN-OHL-W-2.0
- CFITSIO
- CMU-Mach
- CMU-Mach-nodoc
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
- Caldera-no-preamble
- Catharon
ClArtistic
- Clips
- Community-Spec-1.0
Condor-1.1
- Cornell-Lossless-JPEG
- Cronyx
Crossword
CrystalStacker
Cube
D-FSL-1.0
- DEC-3-Clause
- DL-DE-BY-2.0
- DL-DE-ZERO-2.0
DOC
DRL-1.0
- DRL-1.1
DSDP
Dotseqn
ECL-1.0
@@ -224,38 +164,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
- FSFAP-no-warranty-disclaimer
FSFUL
FSFULLR
- FSFULLRWD
FTL
Fair
- Ferguson-Twofish
Frameworx-1.0
FreeBSD-DOC
FreeImage
- Furuseth
- GCR-docs
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
@@ -264,80 +199,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
- Gutmann
- HP-1986
- HP-1989
HPND
- HPND-DEC
- HPND-Fenneberg-Livingston
- HPND-INRIA-IMAG
- HPND-Intel
- HPND-Kevlin-Henney
- HPND-MIT-disclaimer
- HPND-Markus-Kuhn
- HPND-Pbmplus
- HPND-UC
- HPND-UC-export-US
- HPND-doc
- HPND-doc-sell
- HPND-export-US
- HPND-export-US-acknowledgement
- HPND-export-US-modify
- HPND-export2-US
- HPND-merchantability-variant
- HPND-sell-MIT-disclaimer-xserver
- HPND-sell-regexpr
HPND-sell-variant
- HPND-sell-variant-MIT-disclaimer
- HPND-sell-variant-MIT-disclaimer-rev
HTMLTIDY
HaskellReport
Hippocratic-2.1
IBM-pibs
ICU
- IEC-Code-Components-EULA
IJG
- IJG-short
IPA
IPL-1.0
ISC
- ISC-Veillard
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
- LPD-document
LPL-1.0
LPL-1.02
LPPL-1.0
@@ -345,50 +263,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-Khronos-old
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
- Mackerras-3-Clause
- Mackerras-3-Clause-acknowledgment
MakeIndex
- Martin-Birgmeier
- McPhee-slideshow
- Minpack
MirOS
Motosoto
MulanPSL-1.0
@@ -398,17 +296,12 @@ class Gem::Licenses
NAIST-2003
NASA-1.3
NBPL-1.0
- NCBI-PD
NCGL-UK-2.0
- NCL
NCSA
NGPL
- NICTA-1.0
NIST-PD
NIST-PD-fallback
- NIST-Software
NLOD-1.0
- NLOD-2.0
NLPL
NOSL
NPL-1.0
@@ -423,13 +316,12 @@ class Gem::Licenses
Newsletr
Nokia
Noweb
+ Nunit
O-UDA-1.0
- OAR
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
@@ -459,38 +351,27 @@ 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
- OpenSSL-standalone
- OpenVision
- PADL
PDDL-1.0
PHP-3.0
PHP-3.01
- PPL
PSF-2.0
Parity-6.0.0
Parity-7.0.0
- Pixar
Plexus
PolyForm-Noncommercial-1.0.0
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
@@ -501,66 +382,45 @@ class Gem::Licenses
Rdisc
Ruby
SAX-PD
- SAX-PD-2.0
SCEA
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
SPL-1.0
SSH-OpenSSH
SSH-short
- SSLeay-standalone
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
- Sun-PPP
- Sun-PPP-2000
- SunPro
- Symlinks
TAPR-OHL-1.0
TCL
TCP-wrappers
- TGPPL-1.0
TMate
TORQUE-1.1
TOSL
- TPDL
- TPL-1.0
- TTWL
- TTYP0
TU-Berlin-1.0
TU-Berlin-2.0
- TermReadKey
- UCAR
UCL-1.0
- UMich-Merit
UPL-1.0
- URT-RLE
- Unicode-3.0
Unicode-DFS-2015
Unicode-DFS-2016
Unicode-TOU
- UnixCrypt
Unlicense
VOSTROM
VSL-1.0
@@ -570,15 +430,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
@@ -586,109 +442,41 @@ class Gem::Licenses
ZPL-2.0
ZPL-2.1
Zed
- Zeeff
Zend-2.0
Zimbra-1.3
Zimbra-1.4
Zlib
- any-OSI
- bcrypt-Solar-Designer
blessing
+ bzip2-1.0.5
bzip2-1.0.6
- check-cvs
- checkmk
copyleft-next-0.3.0
copyleft-next-0.3.1
curl
- cve-tou
diffmark
- dtoa
dvipdfm
+ eCos-2.0
eGenix
etalab-2.0
- fwlw
gSOAP-1.3b
gnuplot
- gtkbook
- hdparm
iMatix
libpng-2.0
libselinux-1.0
libtiff
- libutil-David-Nugent
- lsof
- magaz
- mailprio
- metamail
- mpi-permissive
mpich2
- mplus
- pkgconf
- pnmstitch
psfrag
psutils
- python-ldap
- radvd
- snprintf
- softSurfer
- ssh-keyscan
- swrule
- threeparttable
- ulem
- w3m
+ wxWindows
xinetd
- xkeyboard-config-Zinoviev
- xlock
xpp
- xzoom
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
- Asterisk-linking-protocols-exception
Autoconf-exception-2.0
Autoconf-exception-3.0
- Autoconf-exception-generic
- Autoconf-exception-generic-3.0
- Autoconf-exception-macro
- Bison-exception-1.24
Bison-exception-2.2
Bootloader-exception
CLISP-exception-2.0
@@ -698,64 +486,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
- GNOME-examples-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
- Gmsh-exception
- 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
- PCRE2-exception
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
- RRDtool-FLOSS-exception-2.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
- fmt-exception
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)}
@@ -765,34 +527,10 @@ class Gem::Licenses
| #{LICENSE_REF}
)
\Z
- /ox
-
- DEPRECATED_LICENSE_REGEXP = /
- \A
- #{Regexp.union(DEPRECATED_LICENSE_IDENTIFIERS)}
- \+?
- (?:\s WITH \s .+?)?
- \Z
- /ox
-
- DEPRECATED_EXCEPTION_REGEXP = /
- \A
- .+?
- \+?
- (?:\s WITH \s #{Regexp.union(DEPRECATED_EXCEPTION_IDENTIFIERS)})
- \Z
- /ox
+ }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..33c40af4bb 100644
--- a/lib/rubygems/util/list.rb
+++ b/lib/rubygems/util/list.rb
@@ -1,8 +1,6 @@
# 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 +34,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..1609924607 100644
--- a/lib/rubygems/validator.rb
+++ b/lib/rubygems/validator.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -25,7 +24,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 +62,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 +87,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 +107,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/vendor/molinillo/.document b/lib/rubygems/vendor/molinillo/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/molinillo/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo.rb b/lib/rubygems/vendor/molinillo/lib/molinillo.rb
deleted file mode 100644
index dd5600c9e3..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'molinillo/gem_metadata'
-require_relative 'molinillo/errors'
-require_relative 'molinillo/resolver'
-require_relative 'molinillo/modules/ui'
-require_relative 'molinillo/modules/specification_provider'
-
-# Gem::Molinillo is a generic dependency resolution algorithm.
-module Gem::Molinillo
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb
deleted file mode 100644
index 34842d46d5..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # @!visibility private
- module Delegates
- # Delegates all {Gem::Molinillo::ResolutionState} methods to a `#state` property.
- module ResolutionState
- # (see Gem::Molinillo::ResolutionState#name)
- def name
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.name
- end
-
- # (see Gem::Molinillo::ResolutionState#requirements)
- def requirements
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.requirements
- end
-
- # (see Gem::Molinillo::ResolutionState#activated)
- def activated
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.activated
- end
-
- # (see Gem::Molinillo::ResolutionState#requirement)
- def requirement
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.requirement
- end
-
- # (see Gem::Molinillo::ResolutionState#possibilities)
- def possibilities
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.possibilities
- end
-
- # (see Gem::Molinillo::ResolutionState#depth)
- def depth
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.depth
- end
-
- # (see Gem::Molinillo::ResolutionState#conflicts)
- def conflicts
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.conflicts
- end
-
- # (see Gem::Molinillo::ResolutionState#unused_unwind_options)
- def unused_unwind_options
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.unused_unwind_options
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb
deleted file mode 100644
index 8417721537..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- module Delegates
- # Delegates all {Gem::Molinillo::SpecificationProvider} methods to a
- # `#specification_provider` property.
- module SpecificationProvider
- # (see Gem::Molinillo::SpecificationProvider#search_for)
- def search_for(dependency)
- with_no_such_dependency_error_handling do
- specification_provider.search_for(dependency)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#dependencies_for)
- def dependencies_for(specification)
- with_no_such_dependency_error_handling do
- specification_provider.dependencies_for(specification)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#requirement_satisfied_by?)
- def requirement_satisfied_by?(requirement, activated, spec)
- with_no_such_dependency_error_handling do
- specification_provider.requirement_satisfied_by?(requirement, activated, spec)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#dependencies_equal?)
- def dependencies_equal?(dependencies, other_dependencies)
- with_no_such_dependency_error_handling do
- specification_provider.dependencies_equal?(dependencies, other_dependencies)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#name_for)
- def name_for(dependency)
- with_no_such_dependency_error_handling do
- specification_provider.name_for(dependency)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#name_for_explicit_dependency_source)
- def name_for_explicit_dependency_source
- with_no_such_dependency_error_handling do
- specification_provider.name_for_explicit_dependency_source
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#name_for_locking_dependency_source)
- def name_for_locking_dependency_source
- with_no_such_dependency_error_handling do
- specification_provider.name_for_locking_dependency_source
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#sort_dependencies)
- def sort_dependencies(dependencies, activated, conflicts)
- with_no_such_dependency_error_handling do
- specification_provider.sort_dependencies(dependencies, activated, conflicts)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#allow_missing?)
- def allow_missing?(dependency)
- with_no_such_dependency_error_handling do
- specification_provider.allow_missing?(dependency)
- end
- end
-
- private
-
- # Ensures any raised {NoSuchDependencyError} has its
- # {NoSuchDependencyError#required_by} set.
- # @yield
- def with_no_such_dependency_error_handling
- yield
- rescue NoSuchDependencyError => error
- if state
- vertex = activated.vertex_named(name_for(error.dependency))
- error.required_by += vertex.incoming_edges.map { |e| e.origin.name }
- error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty?
- end
- raise
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph.rb
deleted file mode 100644
index 2dbbc589dc..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph.rb
+++ /dev/null
@@ -1,255 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../../../vendored_tsort'
-
-require_relative 'dependency_graph/log'
-require_relative 'dependency_graph/vertex'
-
-module Gem::Molinillo
- # A directed acyclic graph that is tuned to hold named dependencies
- class DependencyGraph
- include Enumerable
-
- # Enumerates through the vertices of the graph.
- # @return [Array<Vertex>] The graph's vertices.
- def each
- return vertices.values.each unless block_given?
- vertices.values.each { |v| yield v }
- end
-
- include Gem::TSort
-
- # @!visibility private
- alias tsort_each_node each
-
- # @!visibility private
- def tsort_each_child(vertex, &block)
- vertex.successors.each(&block)
- end
-
- # Topologically sorts the given vertices.
- # @param [Enumerable<Vertex>] vertices the vertices to be sorted, which must
- # all belong to the same graph.
- # @return [Array<Vertex>] The sorted vertices.
- def self.tsort(vertices)
- Gem::TSort.tsort(
- lambda { |b| vertices.each(&b) },
- lambda { |v, &b| (v.successors & vertices).each(&b) }
- )
- end
-
- # A directed edge of a {DependencyGraph}
- # @attr [Vertex] origin The origin of the directed edge
- # @attr [Vertex] destination The destination of the directed edge
- # @attr [Object] requirement The requirement the directed edge represents
- Edge = Struct.new(:origin, :destination, :requirement)
-
- # @return [{String => Vertex}] the vertices of the dependency graph, keyed
- # by {Vertex#name}
- attr_reader :vertices
-
- # @return [Log] the op log for this graph
- attr_reader :log
-
- # Initializes an empty dependency graph
- def initialize
- @vertices = {}
- @log = Log.new
- end
-
- # Tags the current state of the dependency as the given tag
- # @param [Object] tag an opaque tag for the current state of the graph
- # @return [Void]
- def tag(tag)
- log.tag(self, tag)
- end
-
- # Rewinds the graph to the state tagged as `tag`
- # @param [Object] tag the tag to rewind to
- # @return [Void]
- def rewind_to(tag)
- log.rewind_to(self, tag)
- end
-
- # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices}
- # are properly copied.
- # @param [DependencyGraph] other the graph to copy.
- def initialize_copy(other)
- super
- @vertices = {}
- @log = other.log.dup
- traverse = lambda do |new_v, old_v|
- return if new_v.outgoing_edges.size == old_v.outgoing_edges.size
- old_v.outgoing_edges.each do |edge|
- destination = add_vertex(edge.destination.name, edge.destination.payload)
- add_edge_no_circular(new_v, destination, edge.requirement)
- traverse.call(destination, edge.destination)
- end
- end
- other.vertices.each do |name, vertex|
- new_vertex = add_vertex(name, vertex.payload, vertex.root?)
- new_vertex.explicit_requirements.replace(vertex.explicit_requirements)
- traverse.call(new_vertex, vertex)
- end
- end
-
- # @return [String] a string suitable for debugging
- def inspect
- "#{self.class}:#{vertices.values.inspect}"
- end
-
- # @param [Hash] options options for dot output.
- # @return [String] Returns a dot format representation of the graph
- def to_dot(options = {})
- edge_label = options.delete(:edge_label)
- raise ArgumentError, "Unknown options: #{options.keys}" unless options.empty?
-
- dot_vertices = []
- dot_edges = []
- vertices.each do |n, v|
- dot_vertices << " #{n} [label=\"{#{n}|#{v.payload}}\"]"
- v.outgoing_edges.each do |e|
- label = edge_label ? edge_label.call(e) : e.requirement
- dot_edges << " #{e.origin.name} -> #{e.destination.name} [label=#{label.to_s.dump}]"
- end
- end
-
- dot_vertices.uniq!
- dot_vertices.sort!
- dot_edges.uniq!
- dot_edges.sort!
-
- dot = dot_vertices.unshift('digraph G {').push('') + dot_edges.push('}')
- dot.join("\n")
- end
-
- # @param [DependencyGraph] other
- # @return [Boolean] whether the two dependency graphs are equal, determined
- # by a recursive traversal of each {#root_vertices} and its
- # {Vertex#successors}
- def ==(other)
- return false unless other
- return true if equal?(other)
- vertices.each do |name, vertex|
- other_vertex = other.vertex_named(name)
- return false unless other_vertex
- return false unless vertex.payload == other_vertex.payload
- return false unless other_vertex.successors.to_set == vertex.successors.to_set
- end
- end
-
- # @param [String] name
- # @param [Object] payload
- # @param [Array<String>] parent_names
- # @param [Object] requirement the requirement that is requiring the child
- # @return [void]
- def add_child_vertex(name, payload, parent_names, requirement)
- root = !parent_names.delete(nil) { true }
- vertex = add_vertex(name, payload, root)
- vertex.explicit_requirements << requirement if root
- parent_names.each do |parent_name|
- parent_vertex = vertex_named(parent_name)
- add_edge(parent_vertex, vertex, requirement)
- end
- vertex
- end
-
- # Adds a vertex with the given name, or updates the existing one.
- # @param [String] name
- # @param [Object] payload
- # @return [Vertex] the vertex that was added to `self`
- def add_vertex(name, payload, root = false)
- log.add_vertex(self, name, payload, root)
- end
-
- # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
- # removing any non-root vertices that were orphaned in the process
- # @param [String] name
- # @return [Array<Vertex>] the vertices which have been detached
- def detach_vertex_named(name)
- log.detach_vertex_named(self, name)
- end
-
- # @param [String] name
- # @return [Vertex,nil] the vertex with the given name
- def vertex_named(name)
- vertices[name]
- end
-
- # @param [String] name
- # @return [Vertex,nil] the root vertex with the given name
- def root_vertex_named(name)
- vertex = vertex_named(name)
- vertex if vertex && vertex.root?
- end
-
- # Adds a new {Edge} to the dependency graph
- # @param [Vertex] origin
- # @param [Vertex] destination
- # @param [Object] requirement the requirement that this edge represents
- # @return [Edge] the added edge
- def add_edge(origin, destination, requirement)
- if destination.path_to?(origin)
- raise CircularDependencyError.new(path(destination, origin))
- end
- add_edge_no_circular(origin, destination, requirement)
- end
-
- # Deletes an {Edge} from the dependency graph
- # @param [Edge] edge
- # @return [Void]
- def delete_edge(edge)
- log.delete_edge(self, edge.origin.name, edge.destination.name, edge.requirement)
- end
-
- # Sets the payload of the vertex with the given name
- # @param [String] name the name of the vertex
- # @param [Object] payload the payload
- # @return [Void]
- def set_payload(name, payload)
- log.set_payload(self, name, payload)
- end
-
- private
-
- # Adds a new {Edge} to the dependency graph without checking for
- # circularity.
- # @param (see #add_edge)
- # @return (see #add_edge)
- def add_edge_no_circular(origin, destination, requirement)
- log.add_edge_no_circular(self, origin.name, destination.name, requirement)
- end
-
- # Returns the path between two vertices
- # @raise [ArgumentError] if there is no path between the vertices
- # @param [Vertex] from
- # @param [Vertex] to
- # @return [Array<Vertex>] the shortest path from `from` to `to`
- def path(from, to)
- distances = Hash.new(vertices.size + 1)
- distances[from.name] = 0
- predecessors = {}
- each do |vertex|
- vertex.successors.each do |successor|
- if distances[successor.name] > distances[vertex.name] + 1
- distances[successor.name] = distances[vertex.name] + 1
- predecessors[successor] = vertex
- end
- end
- end
-
- path = [to]
- while before = predecessors[to]
- path << before
- to = before
- break if to == from
- end
-
- unless path.last.equal?(from)
- raise ArgumentError, "There is no path from #{from.name} to #{to.name}"
- end
-
- path.reverse
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/action.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/action.rb
deleted file mode 100644
index 8707ec451d..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/action.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- class DependencyGraph
- # An action that modifies a {DependencyGraph} that is reversible.
- # @abstract
- class Action
- # rubocop:disable Lint/UnusedMethodArgument
-
- # @return [Symbol] The name of the action.
- def self.action_name
- raise 'Abstract'
- end
-
- # Performs the action on the given graph.
- # @param [DependencyGraph] graph the graph to perform the action on.
- # @return [Void]
- def up(graph)
- raise 'Abstract'
- end
-
- # Reverses the action on the given graph.
- # @param [DependencyGraph] graph the graph to reverse the action on.
- # @return [Void]
- def down(graph)
- raise 'Abstract'
- end
-
- # @return [Action,Nil] The previous action
- attr_accessor :previous
-
- # @return [Action,Nil] The next action
- attr_accessor :next
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
deleted file mode 100644
index aa9815c5ae..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # (see DependencyGraph#add_edge_no_circular)
- class AddEdgeNoCircular < Action
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :add_vertex
- end
-
- # (see Action#up)
- def up(graph)
- edge = make_edge(graph)
- edge.origin.outgoing_edges << edge
- edge.destination.incoming_edges << edge
- edge
- end
-
- # (see Action#down)
- def down(graph)
- edge = make_edge(graph)
- delete_first(edge.origin.outgoing_edges, edge)
- delete_first(edge.destination.incoming_edges, edge)
- end
-
- # @!group AddEdgeNoCircular
-
- # @return [String] the name of the origin of the edge
- attr_reader :origin
-
- # @return [String] the name of the destination of the edge
- attr_reader :destination
-
- # @return [Object] the requirement that the edge represents
- attr_reader :requirement
-
- # @param [DependencyGraph] graph the graph to find vertices from
- # @return [Edge] The edge this action adds
- def make_edge(graph)
- Edge.new(graph.vertex_named(origin), graph.vertex_named(destination), requirement)
- end
-
- # Initialize an action to add an edge to a dependency graph
- # @param [String] origin the name of the origin of the edge
- # @param [String] destination the name of the destination of the edge
- # @param [Object] requirement the requirement that the edge represents
- def initialize(origin, destination, requirement)
- @origin = origin
- @destination = destination
- @requirement = requirement
- end
-
- private
-
- def delete_first(array, item)
- return unless index = array.index(item)
- array.delete_at(index)
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
deleted file mode 100644
index 9c7066a669..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # (see DependencyGraph#add_vertex)
- class AddVertex < Action # :nodoc:
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :add_vertex
- end
-
- # (see Action#up)
- def up(graph)
- if existing = graph.vertices[name]
- @existing_payload = existing.payload
- @existing_root = existing.root
- end
- vertex = existing || Vertex.new(name, payload)
- graph.vertices[vertex.name] = vertex
- vertex.payload ||= payload
- vertex.root ||= root
- vertex
- end
-
- # (see Action#down)
- def down(graph)
- if defined?(@existing_payload)
- vertex = graph.vertices[name]
- vertex.payload = @existing_payload
- vertex.root = @existing_root
- else
- graph.vertices.delete(name)
- end
- end
-
- # @!group AddVertex
-
- # @return [String] the name of the vertex
- attr_reader :name
-
- # @return [Object] the payload for the vertex
- attr_reader :payload
-
- # @return [Boolean] whether the vertex is root or not
- attr_reader :root
-
- # Initialize an action to add a vertex to a dependency graph
- # @param [String] name the name of the vertex
- # @param [Object] payload the payload for the vertex
- # @param [Boolean] root whether the vertex is root or not
- def initialize(name, payload, root)
- @name = name
- @payload = payload
- @root = root
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
deleted file mode 100644
index 1e62c0a0b6..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # (see DependencyGraph#delete_edge)
- class DeleteEdge < Action
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :delete_edge
- end
-
- # (see Action#up)
- def up(graph)
- edge = make_edge(graph)
- edge.origin.outgoing_edges.delete(edge)
- edge.destination.incoming_edges.delete(edge)
- end
-
- # (see Action#down)
- def down(graph)
- edge = make_edge(graph)
- edge.origin.outgoing_edges << edge
- edge.destination.incoming_edges << edge
- edge
- end
-
- # @!group DeleteEdge
-
- # @return [String] the name of the origin of the edge
- attr_reader :origin_name
-
- # @return [String] the name of the destination of the edge
- attr_reader :destination_name
-
- # @return [Object] the requirement that the edge represents
- attr_reader :requirement
-
- # @param [DependencyGraph] graph the graph to find vertices from
- # @return [Edge] The edge this action adds
- def make_edge(graph)
- Edge.new(
- graph.vertex_named(origin_name),
- graph.vertex_named(destination_name),
- requirement
- )
- end
-
- # Initialize an action to add an edge to a dependency graph
- # @param [String] origin_name the name of the origin of the edge
- # @param [String] destination_name the name of the destination of the edge
- # @param [Object] requirement the requirement that the edge represents
- def initialize(origin_name, destination_name, requirement)
- @origin_name = origin_name
- @destination_name = destination_name
- @requirement = requirement
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
deleted file mode 100644
index 6132f969b9..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # @see DependencyGraph#detach_vertex_named
- class DetachVertexNamed < Action
- # @!group Action
-
- # (see Action#name)
- def self.action_name
- :add_vertex
- end
-
- # (see Action#up)
- def up(graph)
- return [] unless @vertex = graph.vertices.delete(name)
-
- removed_vertices = [@vertex]
- @vertex.outgoing_edges.each do |e|
- v = e.destination
- v.incoming_edges.delete(e)
- if !v.root? && v.incoming_edges.empty?
- removed_vertices.concat graph.detach_vertex_named(v.name)
- end
- end
-
- @vertex.incoming_edges.each do |e|
- v = e.origin
- v.outgoing_edges.delete(e)
- end
-
- removed_vertices
- end
-
- # (see Action#down)
- def down(graph)
- return unless @vertex
- graph.vertices[@vertex.name] = @vertex
- @vertex.outgoing_edges.each do |e|
- e.destination.incoming_edges << e
- end
- @vertex.incoming_edges.each do |e|
- e.origin.outgoing_edges << e
- end
- end
-
- # @!group DetachVertexNamed
-
- # @return [String] the name of the vertex to detach
- attr_reader :name
-
- # Initialize an action to detach a vertex from a dependency graph
- # @param [String] name the name of the vertex to detach
- def initialize(name)
- @name = name
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/log.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/log.rb
deleted file mode 100644
index 6954c4b1f8..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/log.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'add_edge_no_circular'
-require_relative 'add_vertex'
-require_relative 'delete_edge'
-require_relative 'detach_vertex_named'
-require_relative 'set_payload'
-require_relative 'tag'
-
-module Gem::Molinillo
- class DependencyGraph
- # A log for dependency graph actions
- class Log
- # Initializes an empty log
- def initialize
- @current_action = @first_action = nil
- end
-
- # @!macro [new] action
- # {include:DependencyGraph#$0}
- # @param [Graph] graph the graph to perform the action on
- # @param (see DependencyGraph#$0)
- # @return (see DependencyGraph#$0)
-
- # @macro action
- def tag(graph, tag)
- push_action(graph, Tag.new(tag))
- end
-
- # @macro action
- def add_vertex(graph, name, payload, root)
- push_action(graph, AddVertex.new(name, payload, root))
- end
-
- # @macro action
- def detach_vertex_named(graph, name)
- push_action(graph, DetachVertexNamed.new(name))
- end
-
- # @macro action
- def add_edge_no_circular(graph, origin, destination, requirement)
- push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement))
- end
-
- # {include:DependencyGraph#delete_edge}
- # @param [Graph] graph the graph to perform the action on
- # @param [String] origin_name
- # @param [String] destination_name
- # @param [Object] requirement
- # @return (see DependencyGraph#delete_edge)
- def delete_edge(graph, origin_name, destination_name, requirement)
- push_action(graph, DeleteEdge.new(origin_name, destination_name, requirement))
- end
-
- # @macro action
- def set_payload(graph, name, payload)
- push_action(graph, SetPayload.new(name, payload))
- end
-
- # Pops the most recent action from the log and undoes the action
- # @param [DependencyGraph] graph
- # @return [Action] the action that was popped off the log
- def pop!(graph)
- return unless action = @current_action
- unless @current_action = action.previous
- @first_action = nil
- end
- action.down(graph)
- action
- end
-
- extend Enumerable
-
- # @!visibility private
- # Enumerates each action in the log
- # @yield [Action]
- def each
- return enum_for unless block_given?
- action = @first_action
- loop do
- break unless action
- yield action
- action = action.next
- end
- self
- end
-
- # @!visibility private
- # Enumerates each action in the log in reverse order
- # @yield [Action]
- def reverse_each
- return enum_for(:reverse_each) unless block_given?
- action = @current_action
- loop do
- break unless action
- yield action
- action = action.previous
- end
- self
- end
-
- # @macro action
- def rewind_to(graph, tag)
- loop do
- action = pop!(graph)
- raise "No tag #{tag.inspect} found" unless action
- break if action.class.action_name == :tag && action.tag == tag
- end
- end
-
- private
-
- # Adds the given action to the log, running the action
- # @param [DependencyGraph] graph
- # @param [Action] action
- # @return The value returned by `action.up`
- def push_action(graph, action)
- action.previous = @current_action
- @current_action.next = action if @current_action
- @current_action = action
- @first_action ||= action
- action.up(graph)
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb
deleted file mode 100644
index 9bcaaae0f9..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # @see DependencyGraph#set_payload
- class SetPayload < Action # :nodoc:
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :set_payload
- end
-
- # (see Action#up)
- def up(graph)
- vertex = graph.vertex_named(name)
- @old_payload = vertex.payload
- vertex.payload = payload
- end
-
- # (see Action#down)
- def down(graph)
- graph.vertex_named(name).payload = @old_payload
- end
-
- # @!group SetPayload
-
- # @return [String] the name of the vertex
- attr_reader :name
-
- # @return [Object] the payload for the vertex
- attr_reader :payload
-
- # Initialize an action to add set the payload for a vertex in a dependency
- # graph
- # @param [String] name the name of the vertex
- # @param [Object] payload the payload for the vertex
- def initialize(name, payload)
- @name = name
- @payload = payload
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb
deleted file mode 100644
index 62f243a2af..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # @see DependencyGraph#tag
- class Tag < Action
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :tag
- end
-
- # (see Action#up)
- def up(graph)
- end
-
- # (see Action#down)
- def down(graph)
- end
-
- # @!group Tag
-
- # @return [Object] An opaque tag
- attr_reader :tag
-
- # Initialize an action to tag a state of a dependency graph
- # @param [Object] tag an opaque tag
- def initialize(tag)
- @tag = tag
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb
deleted file mode 100644
index 074de369be..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- class DependencyGraph
- # A vertex in a {DependencyGraph} that encapsulates a {#name} and a
- # {#payload}
- class Vertex
- # @return [String] the name of the vertex
- attr_accessor :name
-
- # @return [Object] the payload the vertex holds
- attr_accessor :payload
-
- # @return [Array<Object>] the explicit requirements that required
- # this vertex
- attr_reader :explicit_requirements
-
- # @return [Boolean] whether the vertex is considered a root vertex
- attr_accessor :root
- alias root? root
-
- # Initializes a vertex with the given name and payload.
- # @param [String] name see {#name}
- # @param [Object] payload see {#payload}
- def initialize(name, payload)
- @name = name.frozen? ? name : name.dup.freeze
- @payload = payload
- @explicit_requirements = []
- @outgoing_edges = []
- @incoming_edges = []
- end
-
- # @return [Array<Object>] all of the requirements that required
- # this vertex
- def requirements
- (incoming_edges.map(&:requirement) + explicit_requirements).uniq
- end
-
- # @return [Array<Edge>] the edges of {#graph} that have `self` as their
- # {Edge#origin}
- attr_accessor :outgoing_edges
-
- # @return [Array<Edge>] the edges of {#graph} that have `self` as their
- # {Edge#destination}
- attr_accessor :incoming_edges
-
- # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
- # `self` as their {Edge#destination}
- def predecessors
- incoming_edges.map(&:origin)
- end
-
- # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
- # {#descendent?}
- def recursive_predecessors
- _recursive_predecessors
- end
-
- # @param [Set<Vertex>] vertices the set to add the predecessors to
- # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
- # {#descendent?}
- def _recursive_predecessors(vertices = new_vertex_set)
- incoming_edges.each do |edge|
- vertex = edge.origin
- next unless vertices.add?(vertex)
- vertex._recursive_predecessors(vertices)
- end
-
- vertices
- end
- protected :_recursive_predecessors
-
- # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
- # `self` as their {Edge#origin}
- def successors
- outgoing_edges.map(&:destination)
- end
-
- # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
- # {#ancestor?}
- def recursive_successors
- _recursive_successors
- end
-
- # @param [Set<Vertex>] vertices the set to add the successors to
- # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
- # {#ancestor?}
- def _recursive_successors(vertices = new_vertex_set)
- outgoing_edges.each do |edge|
- vertex = edge.destination
- next unless vertices.add?(vertex)
- vertex._recursive_successors(vertices)
- end
-
- vertices
- end
- protected :_recursive_successors
-
- # @return [String] a string suitable for debugging
- def inspect
- "#{self.class}:#{name}(#{payload.inspect})"
- end
-
- # @return [Boolean] whether the two vertices are equal, determined
- # by a recursive traversal of each {Vertex#successors}
- def ==(other)
- return true if equal?(other)
- shallow_eql?(other) &&
- successors.to_set == other.successors.to_set
- end
-
- # @param [Vertex] other the other vertex to compare to
- # @return [Boolean] whether the two vertices are equal, determined
- # solely by {#name} and {#payload} equality
- def shallow_eql?(other)
- return true if equal?(other)
- other &&
- name == other.name &&
- payload == other.payload
- end
-
- alias eql? ==
-
- # @return [Fixnum] a hash for the vertex based upon its {#name}
- def hash
- name.hash
- end
-
- # Is there a path from `self` to `other` following edges in the
- # dependency graph?
- # @return whether there is a path following edges within this {#graph}
- def path_to?(other)
- _path_to?(other)
- end
-
- alias descendent? path_to?
-
- # @param [Vertex] other the vertex to check if there's a path to
- # @param [Set<Vertex>] visited the vertices of {#graph} that have been visited
- # @return [Boolean] whether there is a path to `other` from `self`
- def _path_to?(other, visited = new_vertex_set)
- return false unless visited.add?(self)
- return true if equal?(other)
- successors.any? { |v| v._path_to?(other, visited) }
- end
- protected :_path_to?
-
- # Is there a path from `other` to `self` following edges in the
- # dependency graph?
- # @return whether there is a path following edges within this {#graph}
- def ancestor?(other)
- other.path_to?(self)
- end
-
- alias is_reachable_from? ancestor?
-
- def new_vertex_set
- require 'set'
- Set.new
- end
- private :new_vertex_set
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/errors.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/errors.rb
deleted file mode 100644
index 07ea5fdf37..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/errors.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # An error that occurred during the resolution process
- class ResolverError < StandardError; end
-
- # An error caused by searching for a dependency that is completely unknown,
- # i.e. has no versions available whatsoever.
- class NoSuchDependencyError < ResolverError
- # @return [Object] the dependency that could not be found
- attr_accessor :dependency
-
- # @return [Array<Object>] the specifications that depended upon {#dependency}
- attr_accessor :required_by
-
- # Initializes a new error with the given missing dependency.
- # @param [Object] dependency @see {#dependency}
- # @param [Array<Object>] required_by @see {#required_by}
- def initialize(dependency, required_by = [])
- @dependency = dependency
- @required_by = required_by.uniq
- super()
- end
-
- # The error message for the missing dependency, including the specifications
- # that had this dependency.
- def message
- sources = required_by.map { |r| "`#{r}`" }.join(' and ')
- message = "Unable to find a specification for `#{dependency}`"
- message += " depended upon by #{sources}" unless sources.empty?
- message
- end
- end
-
- # An error caused by attempting to fulfil a dependency that was circular
- #
- # @note This exception will be thrown if and only if a {Vertex} is added to a
- # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an
- # existing {DependencyGraph::Vertex}
- class CircularDependencyError < ResolverError
- # [Set<Object>] the dependencies responsible for causing the error
- attr_reader :dependencies
-
- # Initializes a new error with the given circular vertices.
- # @param [Array<DependencyGraph::Vertex>] vertices the vertices in the dependency
- # that caused the error
- def initialize(vertices)
- super "There is a circular dependency between #{vertices.map(&:name).join(' and ')}"
- @dependencies = vertices.map { |vertex| vertex.payload.possibilities.last }.to_set
- end
- end
-
- # An error caused by conflicts in version
- class VersionConflict < ResolverError
- # @return [{String => Resolution::Conflict}] the conflicts that caused
- # resolution to fail
- attr_reader :conflicts
-
- # @return [SpecificationProvider] the specification provider used during
- # resolution
- attr_reader :specification_provider
-
- # Initializes a new error with the given version conflicts.
- # @param [{String => Resolution::Conflict}] conflicts see {#conflicts}
- # @param [SpecificationProvider] specification_provider see {#specification_provider}
- def initialize(conflicts, specification_provider)
- pairs = []
- conflicts.values.flat_map(&:requirements).each do |conflicting|
- conflicting.each do |source, conflict_requirements|
- conflict_requirements.each do |c|
- pairs << [c, source]
- end
- end
- end
-
- super "Unable to satisfy the following requirements:\n\n" \
- "#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}"
-
- @conflicts = conflicts
- @specification_provider = specification_provider
- end
-
- require_relative 'delegates/specification_provider'
- include Delegates::SpecificationProvider
-
- # @return [String] An error message that includes requirement trees,
- # which is much more detailed & customizable than the default message
- # @param [Hash] opts the options to create a message with.
- # @option opts [String] :solver_name The user-facing name of the solver
- # @option opts [String] :possibility_type The generic name of a possibility
- # @option opts [Proc] :reduce_trees A proc that reduced the list of requirement trees
- # @option opts [Proc] :printable_requirement A proc that pretty-prints requirements
- # @option opts [Proc] :additional_message_for_conflict A proc that appends additional
- # messages for each conflict
- # @option opts [Proc] :version_for_spec A proc that returns the version number for a
- # possibility
- def message_with_trees(opts = {})
- solver_name = opts.delete(:solver_name) { self.class.name.split('::').first }
- possibility_type = opts.delete(:possibility_type) { 'possibility named' }
- reduce_trees = opts.delete(:reduce_trees) { proc { |trees| trees.uniq.sort_by(&:to_s) } }
- printable_requirement = opts.delete(:printable_requirement) { proc { |req| req.to_s } }
- additional_message_for_conflict = opts.delete(:additional_message_for_conflict) { proc {} }
- version_for_spec = opts.delete(:version_for_spec) { proc(&:to_s) }
- incompatible_version_message_for_conflict = opts.delete(:incompatible_version_message_for_conflict) do
- proc do |name, _conflict|
- %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
- end
- end
-
- full_message_for_conflict = opts.delete(:full_message_for_conflict) do
- proc do |name, conflict|
- o = "\n".dup << incompatible_version_message_for_conflict.call(name, conflict) << "\n"
- if conflict.locked_requirement
- o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
- o << %( #{printable_requirement.call(conflict.locked_requirement)}\n)
- o << %(\n)
- end
- o << %( In #{name_for_explicit_dependency_source}:\n)
- trees = reduce_trees.call(conflict.requirement_trees)
-
- o << trees.map do |tree|
- t = ''.dup
- depth = 2
- tree.each do |req|
- t << ' ' * depth << printable_requirement.call(req)
- unless tree.last == req
- if spec = conflict.activated_by_name[name_for(req)]
- t << %( was resolved to #{version_for_spec.call(spec)}, which)
- end
- t << %( depends on)
- end
- t << %(\n)
- depth += 1
- end
- t
- end.join("\n")
-
- additional_message_for_conflict.call(o, name, conflict)
-
- o
- end
- end
-
- conflicts.sort.reduce(''.dup) do |o, (name, conflict)|
- o << full_message_for_conflict.call(name, conflict)
- end.strip
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/gem_metadata.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/gem_metadata.rb
deleted file mode 100644
index 8ed3a920a2..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/gem_metadata.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # The version of Gem::Molinillo.
- VERSION = '0.8.0'.freeze
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/modules/specification_provider.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/modules/specification_provider.rb
deleted file mode 100644
index 85860902fc..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/modules/specification_provider.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # Provides information about specifications and dependencies to the resolver,
- # allowing the {Resolver} class to remain generic while still providing power
- # and flexibility.
- #
- # This module contains the methods that users of Gem::Molinillo must to implement,
- # using knowledge of their own model classes.
- module SpecificationProvider
- # Search for the specifications that match the given dependency.
- # The specifications in the returned array will be considered in reverse
- # order, so the latest version ought to be last.
- # @note This method should be 'pure', i.e. the return value should depend
- # only on the `dependency` parameter.
- #
- # @param [Object] dependency
- # @return [Array<Object>] the specifications that satisfy the given
- # `dependency`.
- def search_for(dependency)
- []
- end
-
- # Returns the dependencies of `specification`.
- # @note This method should be 'pure', i.e. the return value should depend
- # only on the `specification` parameter.
- #
- # @param [Object] specification
- # @return [Array<Object>] the dependencies that are required by the given
- # `specification`.
- def dependencies_for(specification)
- []
- end
-
- # Determines whether the given `requirement` is satisfied by the given
- # `spec`, in the context of the current `activated` dependency graph.
- #
- # @param [Object] requirement
- # @param [DependencyGraph] activated the current dependency graph in the
- # resolution process.
- # @param [Object] spec
- # @return [Boolean] whether `requirement` is satisfied by `spec` in the
- # context of the current `activated` dependency graph.
- def requirement_satisfied_by?(requirement, activated, spec)
- true
- end
-
- # Determines whether two arrays of dependencies are equal, and thus can be
- # grouped.
- #
- # @param [Array<Object>] dependencies
- # @param [Array<Object>] other_dependencies
- # @return [Boolean] whether `dependencies` and `other_dependencies` should
- # be considered equal.
- def dependencies_equal?(dependencies, other_dependencies)
- dependencies == other_dependencies
- end
-
- # Returns the name for the given `dependency`.
- # @note This method should be 'pure', i.e. the return value should depend
- # only on the `dependency` parameter.
- #
- # @param [Object] dependency
- # @return [String] the name for the given `dependency`.
- def name_for(dependency)
- dependency.to_s
- end
-
- # @return [String] the name of the source of explicit dependencies, i.e.
- # those passed to {Resolver#resolve} directly.
- def name_for_explicit_dependency_source
- 'user-specified dependency'
- end
-
- # @return [String] the name of the source of 'locked' dependencies, i.e.
- # those passed to {Resolver#resolve} directly as the `base`
- def name_for_locking_dependency_source
- 'Lockfile'
- end
-
- # Sort dependencies so that the ones that are easiest to resolve are first.
- # Easiest to resolve is (usually) defined by:
- # 1) Is this dependency already activated?
- # 2) How relaxed are the requirements?
- # 3) Are there any conflicts for this dependency?
- # 4) How many possibilities are there to satisfy this dependency?
- #
- # @param [Array<Object>] dependencies
- # @param [DependencyGraph] activated the current dependency graph in the
- # resolution process.
- # @param [{String => Array<Conflict>}] conflicts
- # @return [Array<Object>] a sorted copy of `dependencies`.
- def sort_dependencies(dependencies, activated, conflicts)
- dependencies.sort_by do |dependency|
- name = name_for(dependency)
- [
- activated.vertex_named(name).payload ? 0 : 1,
- conflicts[name] ? 0 : 1,
- ]
- end
- end
-
- # Returns whether this dependency, which has no possible matching
- # specifications, can safely be ignored.
- #
- # @param [Object] dependency
- # @return [Boolean] whether this dependency can safely be skipped.
- def allow_missing?(dependency)
- false
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/modules/ui.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/modules/ui.rb
deleted file mode 100644
index 464722902e..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/modules/ui.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # Conveys information about the resolution process to a user.
- module UI
- # The {IO} object that should be used to print output. `STDOUT`, by default.
- #
- # @return [IO]
- def output
- STDOUT
- end
-
- # Called roughly every {#progress_rate}, this method should convey progress
- # to the user.
- #
- # @return [void]
- def indicate_progress
- output.print '.' unless debug?
- end
-
- # How often progress should be conveyed to the user via
- # {#indicate_progress}, in seconds. A third of a second, by default.
- #
- # @return [Float]
- def progress_rate
- 0.33
- end
-
- # Called before resolution begins.
- #
- # @return [void]
- def before_resolution
- output.print 'Resolving dependencies...'
- end
-
- # Called after resolution ends (either successfully or with an error).
- # By default, prints a newline.
- #
- # @return [void]
- def after_resolution
- output.puts
- end
-
- # Conveys debug information to the user.
- #
- # @param [Integer] depth the current depth of the resolution process.
- # @return [void]
- def debug(depth = 0)
- if debug?
- debug_info = yield
- debug_info = debug_info.inspect unless debug_info.is_a?(String)
- debug_info = debug_info.split("\n").map { |s| ":#{depth.to_s.rjust 4}: #{s}" }
- output.puts debug_info
- end
- end
-
- # Whether or not debug messages should be printed.
- # By default, whether or not the `MOLINILLO_DEBUG` environment variable is
- # set.
- #
- # @return [Boolean]
- def debug?
- return @debug_mode if defined?(@debug_mode)
- @debug_mode = ENV['MOLINILLO_DEBUG']
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/resolution.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/resolution.rb
deleted file mode 100644
index 84ec6cb095..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/resolution.rb
+++ /dev/null
@@ -1,839 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- class Resolver
- # A specific resolution from a given {Resolver}
- class Resolution
- # A conflict that the resolution process encountered
- # @attr [Object] requirement the requirement that immediately led to the conflict
- # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict
- # @attr [Object, nil] existing the existing spec that was in conflict with
- # the {#possibility}
- # @attr [Object] possibility_set the set of specs that was unable to be
- # activated due to a conflict.
- # @attr [Object] locked_requirement the relevant locking requirement.
- # @attr [Array<Array<Object>>] requirement_trees the different requirement
- # trees that led to every requirement for the conflicting name.
- # @attr [{String=>Object}] activated_by_name the already-activated specs.
- # @attr [Object] underlying_error an error that has occurred during resolution, and
- # will be raised at the end of it if no resolution is found.
- Conflict = Struct.new(
- :requirement,
- :requirements,
- :existing,
- :possibility_set,
- :locked_requirement,
- :requirement_trees,
- :activated_by_name,
- :underlying_error
- )
-
- class Conflict
- # @return [Object] a spec that was unable to be activated due to a conflict
- def possibility
- possibility_set && possibility_set.latest_version
- end
- end
-
- # A collection of possibility states that share the same dependencies
- # @attr [Array] dependencies the dependencies for this set of possibilities
- # @attr [Array] possibilities the possibilities
- PossibilitySet = Struct.new(:dependencies, :possibilities)
-
- class PossibilitySet
- # String representation of the possibility set, for debugging
- def to_s
- "[#{possibilities.join(', ')}]"
- end
-
- # @return [Object] most up-to-date dependency in the possibility set
- def latest_version
- possibilities.last
- end
- end
-
- # Details of the state to unwind to when a conflict occurs, and the cause of the unwind
- # @attr [Integer] state_index the index of the state to unwind to
- # @attr [Object] state_requirement the requirement of the state we're unwinding to
- # @attr [Array] requirement_tree for the requirement we're relaxing
- # @attr [Array] conflicting_requirements the requirements that combined to cause the conflict
- # @attr [Array] requirement_trees for the conflict
- # @attr [Array] requirements_unwound_to_instead array of unwind requirements that were chosen over this unwind
- UnwindDetails = Struct.new(
- :state_index,
- :state_requirement,
- :requirement_tree,
- :conflicting_requirements,
- :requirement_trees,
- :requirements_unwound_to_instead
- )
-
- class UnwindDetails
- include Comparable
-
- # We compare UnwindDetails when choosing which state to unwind to. If
- # two options have the same state_index we prefer the one most
- # removed from a requirement that caused the conflict. Both options
- # would unwind to the same state, but a `grandparent` option will
- # filter out fewer of its possibilities after doing so - where a state
- # is both a `parent` and a `grandparent` to requirements that have
- # caused a conflict this is the correct behaviour.
- # @param [UnwindDetail] other UnwindDetail to be compared
- # @return [Integer] integer specifying ordering
- def <=>(other)
- if state_index > other.state_index
- 1
- elsif state_index == other.state_index
- reversed_requirement_tree_index <=> other.reversed_requirement_tree_index
- else
- -1
- end
- end
-
- # @return [Integer] index of state requirement in reversed requirement tree
- # (the conflicting requirement itself will be at position 0)
- def reversed_requirement_tree_index
- @reversed_requirement_tree_index ||=
- if state_requirement
- requirement_tree.reverse.index(state_requirement)
- else
- 999_999
- end
- end
-
- # @return [Boolean] where the requirement of the state we're unwinding
- # to directly caused the conflict. Note: in this case, it is
- # impossible for the state we're unwinding to be a parent of
- # any of the other conflicting requirements (or we would have
- # circularity)
- def unwinding_to_primary_requirement?
- requirement_tree.last == state_requirement
- end
-
- # @return [Array] array of sub-dependencies to avoid when choosing a
- # new possibility for the state we've unwound to. Only relevant for
- # non-primary unwinds
- def sub_dependencies_to_avoid
- @requirements_to_avoid ||=
- requirement_trees.map do |tree|
- index = tree.index(state_requirement)
- tree[index + 1] if index
- end.compact
- end
-
- # @return [Array] array of all the requirements that led to the need for
- # this unwind
- def all_requirements
- @all_requirements ||= requirement_trees.flatten(1)
- end
- end
-
- # @return [SpecificationProvider] the provider that knows about
- # dependencies, requirements, specifications, versions, etc.
- attr_reader :specification_provider
-
- # @return [UI] the UI that knows how to communicate feedback about the
- # resolution process back to the user
- attr_reader :resolver_ui
-
- # @return [DependencyGraph] the base dependency graph to which
- # dependencies should be 'locked'
- attr_reader :base
-
- # @return [Array] the dependencies that were explicitly required
- attr_reader :original_requested
-
- # Initializes a new resolution.
- # @param [SpecificationProvider] specification_provider
- # see {#specification_provider}
- # @param [UI] resolver_ui see {#resolver_ui}
- # @param [Array] requested see {#original_requested}
- # @param [DependencyGraph] base see {#base}
- def initialize(specification_provider, resolver_ui, requested, base)
- @specification_provider = specification_provider
- @resolver_ui = resolver_ui
- @original_requested = requested
- @base = base
- @states = []
- @iteration_counter = 0
- @parents_of = Hash.new { |h, k| h[k] = [] }
- end
-
- # Resolves the {#original_requested} dependencies into a full dependency
- # graph
- # @raise [ResolverError] if successful resolution is impossible
- # @return [DependencyGraph] the dependency graph of successfully resolved
- # dependencies
- def resolve
- start_resolution
-
- while state
- break if !state.requirement && state.requirements.empty?
- indicate_progress
- if state.respond_to?(:pop_possibility_state) # DependencyState
- debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" }
- state.pop_possibility_state.tap do |s|
- if s
- states.push(s)
- activated.tag(s)
- end
- end
- end
- process_topmost_state
- end
-
- resolve_activated_specs
- ensure
- end_resolution
- end
-
- # @return [Integer] the number of resolver iterations in between calls to
- # {#resolver_ui}'s {UI#indicate_progress} method
- attr_accessor :iteration_rate
- private :iteration_rate
-
- # @return [Time] the time at which resolution began
- attr_accessor :started_at
- private :started_at
-
- # @return [Array<ResolutionState>] the stack of states for the resolution
- attr_accessor :states
- private :states
-
- private
-
- # Sets up the resolution process
- # @return [void]
- def start_resolution
- @started_at = Time.now
-
- push_initial_state
-
- debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" }
- resolver_ui.before_resolution
- end
-
- def resolve_activated_specs
- activated.vertices.each do |_, vertex|
- next unless vertex.payload
-
- latest_version = vertex.payload.possibilities.reverse_each.find do |possibility|
- vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) }
- end
-
- activated.set_payload(vertex.name, latest_version)
- end
- activated.freeze
- end
-
- # Ends the resolution process
- # @return [void]
- def end_resolution
- resolver_ui.after_resolution
- debug do
- "Finished resolution (#{@iteration_counter} steps) " \
- "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})"
- end
- debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state
- debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state
- end
-
- require_relative 'state'
- require_relative 'modules/specification_provider'
-
- require_relative 'delegates/resolution_state'
- require_relative 'delegates/specification_provider'
-
- include Gem::Molinillo::Delegates::ResolutionState
- include Gem::Molinillo::Delegates::SpecificationProvider
-
- # Processes the topmost available {RequirementState} on the stack
- # @return [void]
- def process_topmost_state
- if possibility
- attempt_to_activate
- else
- create_conflict
- unwind_for_conflict
- end
- rescue CircularDependencyError => underlying_error
- create_conflict(underlying_error)
- unwind_for_conflict
- end
-
- # @return [Object] the current possibility that the resolution is trying
- # to activate
- def possibility
- possibilities.last
- end
-
- # @return [RequirementState] the current state the resolution is
- # operating upon
- def state
- states.last
- end
-
- # Creates and pushes the initial state for the resolution, based upon the
- # {#requested} dependencies
- # @return [void]
- def push_initial_state
- graph = DependencyGraph.new.tap do |dg|
- original_requested.each do |requested|
- vertex = dg.add_vertex(name_for(requested), nil, true)
- vertex.explicit_requirements << requested
- end
- dg.tag(:initial_state)
- end
-
- push_state_for_requirements(original_requested, true, graph)
- end
-
- # Unwinds the states stack because a conflict has been encountered
- # @return [void]
- def unwind_for_conflict
- details_for_unwind = build_details_for_unwind
- unwind_options = unused_unwind_options
- debug(depth) { "Unwinding for conflict: #{requirement} to #{details_for_unwind.state_index / 2}" }
- conflicts.tap do |c|
- sliced_states = states.slice!((details_for_unwind.state_index + 1)..-1)
- raise_error_unless_state(c)
- activated.rewind_to(sliced_states.first || :initial_state) if sliced_states
- state.conflicts = c
- state.unused_unwind_options = unwind_options
- filter_possibilities_after_unwind(details_for_unwind)
- index = states.size - 1
- @parents_of.each { |_, a| a.reject! { |i| i >= index } }
- state.unused_unwind_options.reject! { |uw| uw.state_index >= index }
- end
- end
-
- # Raises a VersionConflict error, or any underlying error, if there is no
- # current state
- # @return [void]
- def raise_error_unless_state(conflicts)
- return if state
-
- error = conflicts.values.map(&:underlying_error).compact.first
- raise error || VersionConflict.new(conflicts, specification_provider)
- end
-
- # @return [UnwindDetails] Details of the nearest index to which we could unwind
- def build_details_for_unwind
- # Get the possible unwinds for the current conflict
- current_conflict = conflicts[name]
- binding_requirements = binding_requirements_for_conflict(current_conflict)
- unwind_details = unwind_options_for_requirements(binding_requirements)
-
- last_detail_for_current_unwind = unwind_details.sort.last
- current_detail = last_detail_for_current_unwind
-
- # Look for past conflicts that could be unwound to affect the
- # requirement tree for the current conflict
- all_reqs = last_detail_for_current_unwind.all_requirements
- all_reqs_size = all_reqs.size
- relevant_unused_unwinds = unused_unwind_options.select do |alternative|
- diff_reqs = all_reqs - alternative.requirements_unwound_to_instead
- next if diff_reqs.size == all_reqs_size
- # Find the highest index unwind whilst looping through
- current_detail = alternative if alternative > current_detail
- alternative
- end
-
- # Add the current unwind options to the `unused_unwind_options` array.
- # The "used" option will be filtered out during `unwind_for_conflict`.
- state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 }
-
- # Update the requirements_unwound_to_instead on any relevant unused unwinds
- relevant_unused_unwinds.each do |d|
- (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
- end
- unwind_details.each do |d|
- (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
- end
-
- current_detail
- end
-
- # @param [Array<Object>] binding_requirements array of requirements that combine to create a conflict
- # @return [Array<UnwindDetails>] array of UnwindDetails that have a chance
- # of resolving the passed requirements
- def unwind_options_for_requirements(binding_requirements)
- unwind_details = []
-
- trees = []
- binding_requirements.reverse_each do |r|
- partial_tree = [r]
- trees << partial_tree
- unwind_details << UnwindDetails.new(-1, nil, partial_tree, binding_requirements, trees, [])
-
- # If this requirement has alternative possibilities, check if any would
- # satisfy the other requirements that created this conflict
- requirement_state = find_state_for(r)
- if conflict_fixing_possibilities?(requirement_state, binding_requirements)
- unwind_details << UnwindDetails.new(
- states.index(requirement_state),
- r,
- partial_tree,
- binding_requirements,
- trees,
- []
- )
- end
-
- # Next, look at the parent of this requirement, and check if the requirement
- # could have been avoided if an alternative PossibilitySet had been chosen
- parent_r = parent_of(r)
- next if parent_r.nil?
- partial_tree.unshift(parent_r)
- requirement_state = find_state_for(parent_r)
- if requirement_state.possibilities.any? { |set| !set.dependencies.include?(r) }
- unwind_details << UnwindDetails.new(
- states.index(requirement_state),
- parent_r,
- partial_tree,
- binding_requirements,
- trees,
- []
- )
- end
-
- # Finally, look at the grandparent and up of this requirement, looking
- # for any possibilities that wouldn't create their parent requirement
- grandparent_r = parent_of(parent_r)
- until grandparent_r.nil?
- partial_tree.unshift(grandparent_r)
- requirement_state = find_state_for(grandparent_r)
- if requirement_state.possibilities.any? { |set| !set.dependencies.include?(parent_r) }
- unwind_details << UnwindDetails.new(
- states.index(requirement_state),
- grandparent_r,
- partial_tree,
- binding_requirements,
- trees,
- []
- )
- end
- parent_r = grandparent_r
- grandparent_r = parent_of(parent_r)
- end
- end
-
- unwind_details
- end
-
- # @param [DependencyState] state
- # @param [Array] binding_requirements array of requirements
- # @return [Boolean] whether or not the given state has any possibilities
- # that could satisfy the given requirements
- def conflict_fixing_possibilities?(state, binding_requirements)
- return false unless state
-
- state.possibilities.any? do |possibility_set|
- possibility_set.possibilities.any? do |poss|
- possibility_satisfies_requirements?(poss, binding_requirements)
- end
- end
- end
-
- # Filter's a state's possibilities to remove any that would not fix the
- # conflict we've just rewound from
- # @param [UnwindDetails] unwind_details details of the conflict just
- # unwound from
- # @return [void]
- def filter_possibilities_after_unwind(unwind_details)
- return unless state && !state.possibilities.empty?
-
- if unwind_details.unwinding_to_primary_requirement?
- filter_possibilities_for_primary_unwind(unwind_details)
- else
- filter_possibilities_for_parent_unwind(unwind_details)
- end
- end
-
- # Filter's a state's possibilities to remove any that would not satisfy
- # the requirements in the conflict we've just rewound from
- # @param [UnwindDetails] unwind_details details of the conflict just unwound from
- # @return [void]
- def filter_possibilities_for_primary_unwind(unwind_details)
- unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
- unwinds_to_state << unwind_details
- unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements)
-
- state.possibilities.reject! do |possibility_set|
- possibility_set.possibilities.none? do |poss|
- unwind_requirement_sets.any? do |requirements|
- possibility_satisfies_requirements?(poss, requirements)
- end
- end
- end
- end
-
- # @param [Object] possibility a single possibility
- # @param [Array] requirements an array of requirements
- # @return [Boolean] whether the possibility satisfies all of the
- # given requirements
- def possibility_satisfies_requirements?(possibility, requirements)
- name = name_for(possibility)
-
- activated.tag(:swap)
- activated.set_payload(name, possibility) if activated.vertex_named(name)
- satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) }
- activated.rewind_to(:swap)
-
- satisfied
- end
-
- # Filter's a state's possibilities to remove any that would (eventually)
- # create a requirement in the conflict we've just rewound from
- # @param [UnwindDetails] unwind_details details of the conflict just unwound from
- # @return [void]
- def filter_possibilities_for_parent_unwind(unwind_details)
- unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
- unwinds_to_state << unwind_details
-
- primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq
- parent_unwinds = unwinds_to_state.uniq - primary_unwinds
-
- allowed_possibility_sets = primary_unwinds.flat_map do |unwind|
- states[unwind.state_index].possibilities.select do |possibility_set|
- possibility_set.possibilities.any? do |poss|
- possibility_satisfies_requirements?(poss, unwind.conflicting_requirements)
- end
- end
- end
-
- requirements_to_avoid = parent_unwinds.flat_map(&:sub_dependencies_to_avoid)
-
- state.possibilities.reject! do |possibility_set|
- !allowed_possibility_sets.include?(possibility_set) &&
- (requirements_to_avoid - possibility_set.dependencies).empty?
- end
- end
-
- # @param [Conflict] conflict
- # @return [Array] minimal array of requirements that would cause the passed
- # conflict to occur.
- def binding_requirements_for_conflict(conflict)
- return [conflict.requirement] if conflict.possibility.nil?
-
- possible_binding_requirements = conflict.requirements.values.flatten(1).uniq
-
- # When there's a `CircularDependency` error the conflicting requirement
- # (the one causing the circular) won't be `conflict.requirement`
- # (which won't be for the right state, because we won't have created it,
- # because it's circular).
- # We need to make sure we have that requirement in the conflict's list,
- # otherwise we won't be able to unwind properly, so we just return all
- # the requirements for the conflict.
- return possible_binding_requirements if conflict.underlying_error
-
- possibilities = search_for(conflict.requirement)
-
- # If all the requirements together don't filter out all possibilities,
- # then the only two requirements we need to consider are the initial one
- # (where the dependency's version was first chosen) and the last
- if binding_requirement_in_set?(nil, possible_binding_requirements, possibilities)
- return [conflict.requirement, requirement_for_existing_name(name_for(conflict.requirement))].compact
- end
-
- # Loop through the possible binding requirements, removing each one
- # that doesn't bind. Use a `reverse_each` as we want the earliest set of
- # binding requirements, and don't use `reject!` as we wish to refine the
- # array *on each iteration*.
- binding_requirements = possible_binding_requirements.dup
- possible_binding_requirements.reverse_each do |req|
- next if req == conflict.requirement
- unless binding_requirement_in_set?(req, binding_requirements, possibilities)
- binding_requirements -= [req]
- end
- end
-
- binding_requirements
- end
-
- # @param [Object] requirement we wish to check
- # @param [Array] possible_binding_requirements array of requirements
- # @param [Array] possibilities array of possibilities the requirements will be used to filter
- # @return [Boolean] whether or not the given requirement is required to filter
- # out all elements of the array of possibilities.
- def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities)
- possibilities.any? do |poss|
- possibility_satisfies_requirements?(poss, possible_binding_requirements - [requirement])
- end
- end
-
- # @param [Object] requirement
- # @return [Object] the requirement that led to `requirement` being added
- # to the list of requirements.
- def parent_of(requirement)
- return unless requirement
- return unless index = @parents_of[requirement].last
- return unless parent_state = @states[index]
- parent_state.requirement
- end
-
- # @param [String] name
- # @return [Object] the requirement that led to a version of a possibility
- # with the given name being activated.
- def requirement_for_existing_name(name)
- return nil unless vertex = activated.vertex_named(name)
- return nil unless vertex.payload
- states.find { |s| s.name == name }.requirement
- end
-
- # @param [Object] requirement
- # @return [ResolutionState] the state whose `requirement` is the given
- # `requirement`.
- def find_state_for(requirement)
- return nil unless requirement
- states.find { |i| requirement == i.requirement }
- end
-
- # @param [Object] underlying_error
- # @return [Conflict] a {Conflict} that reflects the failure to activate
- # the {#possibility} in conjunction with the current {#state}
- def create_conflict(underlying_error = nil)
- vertex = activated.vertex_named(name)
- locked_requirement = locked_requirement_named(name)
-
- requirements = {}
- unless vertex.explicit_requirements.empty?
- requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements
- end
- requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement
- vertex.incoming_edges.each do |edge|
- (requirements[edge.origin.payload.latest_version] ||= []).unshift(edge.requirement)
- end
-
- activated_by_name = {}
- activated.each { |v| activated_by_name[v.name] = v.payload.latest_version if v.payload }
- conflicts[name] = Conflict.new(
- requirement,
- requirements,
- vertex.payload && vertex.payload.latest_version,
- possibility,
- locked_requirement,
- requirement_trees,
- activated_by_name,
- underlying_error
- )
- end
-
- # @return [Array<Array<Object>>] The different requirement
- # trees that led to every requirement for the current spec.
- def requirement_trees
- vertex = activated.vertex_named(name)
- vertex.requirements.map { |r| requirement_tree_for(r) }
- end
-
- # @param [Object] requirement
- # @return [Array<Object>] the list of requirements that led to
- # `requirement` being required.
- def requirement_tree_for(requirement)
- tree = []
- while requirement
- tree.unshift(requirement)
- requirement = parent_of(requirement)
- end
- tree
- end
-
- # Indicates progress roughly once every second
- # @return [void]
- def indicate_progress
- @iteration_counter += 1
- @progress_rate ||= resolver_ui.progress_rate
- if iteration_rate.nil?
- if Time.now - started_at >= @progress_rate
- self.iteration_rate = @iteration_counter
- end
- end
-
- if iteration_rate && (@iteration_counter % iteration_rate) == 0
- resolver_ui.indicate_progress
- end
- end
-
- # Calls the {#resolver_ui}'s {UI#debug} method
- # @param [Integer] depth the depth of the {#states} stack
- # @param [Proc] block a block that yields a {#to_s}
- # @return [void]
- def debug(depth = 0, &block)
- resolver_ui.debug(depth, &block)
- end
-
- # Attempts to activate the current {#possibility}
- # @return [void]
- def attempt_to_activate
- debug(depth) { 'Attempting to activate ' + possibility.to_s }
- existing_vertex = activated.vertex_named(name)
- if existing_vertex.payload
- debug(depth) { "Found existing spec (#{existing_vertex.payload})" }
- attempt_to_filter_existing_spec(existing_vertex)
- else
- latest = possibility.latest_version
- possibility.possibilities.select! do |possibility|
- requirement_satisfied_by?(requirement, activated, possibility)
- end
- if possibility.latest_version.nil?
- # ensure there's a possibility for better error messages
- possibility.possibilities << latest if latest
- create_conflict
- unwind_for_conflict
- else
- activate_new_spec
- end
- end
- end
-
- # Attempts to update the existing vertex's `PossibilitySet` with a filtered version
- # @return [void]
- def attempt_to_filter_existing_spec(vertex)
- filtered_set = filtered_possibility_set(vertex)
- if !filtered_set.possibilities.empty?
- activated.set_payload(name, filtered_set)
- new_requirements = requirements.dup
- push_state_for_requirements(new_requirements, false)
- else
- create_conflict
- debug(depth) { "Unsatisfied by existing spec (#{vertex.payload})" }
- unwind_for_conflict
- end
- end
-
- # Generates a filtered version of the existing vertex's `PossibilitySet` using the
- # current state's `requirement`
- # @param [Object] vertex existing vertex
- # @return [PossibilitySet] filtered possibility set
- def filtered_possibility_set(vertex)
- PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities)
- end
-
- # @param [String] requirement_name the spec name to search for
- # @return [Object] the locked spec named `requirement_name`, if one
- # is found on {#base}
- def locked_requirement_named(requirement_name)
- vertex = base.vertex_named(requirement_name)
- vertex && vertex.payload
- end
-
- # Add the current {#possibility} to the dependency graph of the current
- # {#state}
- # @return [void]
- def activate_new_spec
- conflicts.delete(name)
- debug(depth) { "Activated #{name} at #{possibility}" }
- activated.set_payload(name, possibility)
- require_nested_dependencies_for(possibility)
- end
-
- # Requires the dependencies that the recently activated spec has
- # @param [Object] possibility_set the PossibilitySet that has just been
- # activated
- # @return [void]
- def require_nested_dependencies_for(possibility_set)
- nested_dependencies = dependencies_for(possibility_set.latest_version)
- debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" }
- nested_dependencies.each do |d|
- activated.add_child_vertex(name_for(d), nil, [name_for(possibility_set.latest_version)], d)
- parent_index = states.size - 1
- parents = @parents_of[d]
- parents << parent_index if parents.empty?
- end
-
- push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?)
- end
-
- # Pushes a new {DependencyState} that encapsulates both existing and new
- # requirements
- # @param [Array] new_requirements
- # @param [Boolean] requires_sort
- # @param [Object] new_activated
- # @return [void]
- def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated)
- new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort
- new_requirement = nil
- loop do
- new_requirement = new_requirements.shift
- break if new_requirement.nil? || states.none? { |s| s.requirement == new_requirement }
- end
- new_name = new_requirement ? name_for(new_requirement) : ''.freeze
- possibilities = possibilities_for_requirement(new_requirement)
- handle_missing_or_push_dependency_state DependencyState.new(
- new_name, new_requirements, new_activated,
- new_requirement, possibilities, depth, conflicts.dup, unused_unwind_options.dup
- )
- end
-
- # Checks a proposed requirement with any existing locked requirement
- # before generating an array of possibilities for it.
- # @param [Object] requirement the proposed requirement
- # @param [Object] activated
- # @return [Array] possibilities
- def possibilities_for_requirement(requirement, activated = self.activated)
- return [] unless requirement
- if locked_requirement_named(name_for(requirement))
- return locked_requirement_possibility_set(requirement, activated)
- end
-
- group_possibilities(search_for(requirement))
- end
-
- # @param [Object] requirement the proposed requirement
- # @param [Object] activated
- # @return [Array] possibility set containing only the locked requirement, if any
- def locked_requirement_possibility_set(requirement, activated = self.activated)
- all_possibilities = search_for(requirement)
- locked_requirement = locked_requirement_named(name_for(requirement))
-
- # Longwinded way to build a possibilities array with either the locked
- # requirement or nothing in it. Required, since the API for
- # locked_requirement isn't guaranteed.
- locked_possibilities = all_possibilities.select do |possibility|
- requirement_satisfied_by?(locked_requirement, activated, possibility)
- end
-
- group_possibilities(locked_possibilities)
- end
-
- # Build an array of PossibilitySets, with each element representing a group of
- # dependency versions that all have the same sub-dependency version constraints
- # and are contiguous.
- # @param [Array] possibilities an array of possibilities
- # @return [Array<PossibilitySet>] an array of possibility sets
- def group_possibilities(possibilities)
- possibility_sets = []
- current_possibility_set = nil
-
- possibilities.reverse_each do |possibility|
- dependencies = dependencies_for(possibility)
- if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies)
- current_possibility_set.possibilities.unshift(possibility)
- else
- possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility]))
- current_possibility_set = possibility_sets.first
- end
- end
-
- possibility_sets
- end
-
- # Pushes a new {DependencyState}.
- # If the {#specification_provider} says to
- # {SpecificationProvider#allow_missing?} that particular requirement, and
- # there are no possibilities for that requirement, then `state` is not
- # pushed, and the vertex in {#activated} is removed, and we continue
- # resolving the remaining requirements.
- # @param [DependencyState] state
- # @return [void]
- def handle_missing_or_push_dependency_state(state)
- if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement)
- state.activated.detach_vertex_named(state.name)
- push_state_for_requirements(state.requirements.dup, false, state.activated)
- else
- states.push(state).tap { activated.tag(state) }
- end
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/resolver.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/resolver.rb
deleted file mode 100644
index 86229c3fa1..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/resolver.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'dependency_graph'
-
-module Gem::Molinillo
- # This class encapsulates a dependency resolver.
- # The resolver is responsible for determining which set of dependencies to
- # activate, with feedback from the {#specification_provider}
- #
- #
- class Resolver
- require_relative 'resolution'
-
- # @return [SpecificationProvider] the specification provider used
- # in the resolution process
- attr_reader :specification_provider
-
- # @return [UI] the UI module used to communicate back to the user
- # during the resolution process
- attr_reader :resolver_ui
-
- # Initializes a new resolver.
- # @param [SpecificationProvider] specification_provider
- # see {#specification_provider}
- # @param [UI] resolver_ui
- # see {#resolver_ui}
- def initialize(specification_provider, resolver_ui)
- @specification_provider = specification_provider
- @resolver_ui = resolver_ui
- end
-
- # Resolves the requested dependencies into a {DependencyGraph},
- # locking to the base dependency graph (if specified)
- # @param [Array] requested an array of 'requested' dependencies that the
- # {#specification_provider} can understand
- # @param [DependencyGraph,nil] base the base dependency graph to which
- # dependencies should be 'locked'
- def resolve(requested, base = DependencyGraph.new)
- Resolution.new(specification_provider,
- resolver_ui,
- requested,
- base).
- resolve
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/state.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/state.rb
deleted file mode 100644
index c48ec6af9c..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/state.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # A state that a {Resolution} can be in
- # @attr [String] name the name of the current requirement
- # @attr [Array<Object>] requirements currently unsatisfied requirements
- # @attr [DependencyGraph] activated the graph of activated dependencies
- # @attr [Object] requirement the current requirement
- # @attr [Object] possibilities the possibilities to satisfy the current requirement
- # @attr [Integer] depth the depth of the resolution
- # @attr [Hash] conflicts unresolved conflicts, indexed by dependency name
- # @attr [Array<UnwindDetails>] unused_unwind_options unwinds for previous conflicts that weren't explored
- ResolutionState = Struct.new(
- :name,
- :requirements,
- :activated,
- :requirement,
- :possibilities,
- :depth,
- :conflicts,
- :unused_unwind_options
- )
-
- class ResolutionState
- # Returns an empty resolution state
- # @return [ResolutionState] an empty state
- def self.empty
- new(nil, [], DependencyGraph.new, nil, nil, 0, {}, [])
- end
- end
-
- # A state that encapsulates a set of {#requirements} with an {Array} of
- # possibilities
- class DependencyState < ResolutionState
- # Removes a possibility from `self`
- # @return [PossibilityState] a state with a single possibility,
- # the possibility that was removed from `self`
- def pop_possibility_state
- PossibilityState.new(
- name,
- requirements.dup,
- activated,
- requirement,
- [possibilities.pop],
- depth + 1,
- conflicts.dup,
- unused_unwind_options.dup
- ).tap do |state|
- state.activated.tag(state)
- end
- end
- end
-
- # A state that encapsulates a single possibility to fulfill the given
- # {#requirement}
- class PossibilityState < ResolutionState
- end
-end
diff --git a/lib/rubygems/vendor/net-http/.document b/lib/rubygems/vendor/net-http/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/net-http/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/net-http/lib/net/http.rb b/lib/rubygems/vendor/net-http/lib/net/http.rb
deleted file mode 100644
index 1a7074819d..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http.rb
+++ /dev/null
@@ -1,2496 +0,0 @@
-# frozen_string_literal: true
-#
-# = net/http.rb
-#
-# Copyright (c) 1999-2007 Yukihiro Matsumoto
-# Copyright (c) 1999-2007 Minero Aoki
-# Copyright (c) 2001 GOTOU Yuuzou
-#
-# Written and maintained by Minero Aoki <aamine@loveruby.net>.
-# HTTPS support added by GOTOU Yuuzou <gotoyuzo@notwork.org>.
-#
-# This file is derived from "http-access.rb".
-#
-# Documented by Minero Aoki; converted to RDoc by William Webber.
-#
-# This program is free software. You can re-distribute and/or
-# modify this program under the same terms of ruby itself ---
-# Ruby Distribution License or GNU General Public License.
-#
-# See Gem::Net::HTTP for an overview and examples.
-#
-
-require_relative '../../../net-protocol/lib/net/protocol'
-require_relative '../../../uri/lib/uri'
-require_relative '../../../resolv/lib/resolv'
-autoload :OpenSSL, 'openssl'
-
-module Gem::Net #:nodoc:
-
- # :stopdoc:
- class HTTPBadResponse < StandardError; end
- class HTTPHeaderSyntaxError < StandardError; end
- # :startdoc:
-
- # \Class \Gem::Net::HTTP provides a rich library that implements the client
- # in a client-server model that uses the \HTTP request-response protocol.
- # For information about \HTTP, see:
- #
- # - {Hypertext Transfer Protocol}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol].
- # - {Technical overview}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Technical_overview].
- #
- # == About the Examples
- #
- # :include: doc/net-http/examples.rdoc
- #
- # == Strategies
- #
- # - If you will make only a few GET requests,
- # consider using {OpenURI}[rdoc-ref:OpenURI].
- # - If you will make only a few requests of all kinds,
- # consider using the various singleton convenience methods in this class.
- # Each of the following methods automatically starts and finishes
- # a {session}[rdoc-ref:Gem::Net::HTTP@Sessions] that sends a single request:
- #
- # # Return string response body.
- # Gem::Net::HTTP.get(hostname, path)
- # Gem::Net::HTTP.get(uri)
- #
- # # Write string response body to $stdout.
- # Gem::Net::HTTP.get_print(hostname, path)
- # Gem::Net::HTTP.get_print(uri)
- #
- # # Return response as Gem::Net::HTTPResponse object.
- # Gem::Net::HTTP.get_response(hostname, path)
- # Gem::Net::HTTP.get_response(uri)
- # data = '{"title": "foo", "body": "bar", "userId": 1}'
- # Gem::Net::HTTP.post(uri, data)
- # params = {title: 'foo', body: 'bar', userId: 1}
- # Gem::Net::HTTP.post_form(uri, params)
- #
- # - If performance is important, consider using sessions, which lower request overhead.
- # This {session}[rdoc-ref:Gem::Net::HTTP@Sessions] has multiple requests for
- # {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods]
- # and {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
- #
- # Gem::Net::HTTP.start(hostname) do |http|
- # # Session started automatically before block execution.
- # http.get(path)
- # http.head(path)
- # body = 'Some text'
- # http.post(path, body) # Can also have a block.
- # http.put(path, body)
- # http.delete(path)
- # http.options(path)
- # http.trace(path)
- # http.patch(path, body) # Can also have a block.
- # http.copy(path)
- # http.lock(path, body)
- # http.mkcol(path, body)
- # http.move(path)
- # http.propfind(path, body)
- # http.proppatch(path, body)
- # http.unlock(path, body)
- # # Session finished automatically at block exit.
- # end
- #
- # The methods cited above are convenience methods that, via their few arguments,
- # allow minimal control over the requests.
- # For greater control, consider using {request objects}[rdoc-ref:Gem::Net::HTTPRequest].
- #
- # == URIs
- #
- # On the internet, a URI
- # ({Universal Resource Identifier}[https://en.wikipedia.org/wiki/Uniform_Resource_Identifier])
- # is a string that identifies a particular resource.
- # It consists of some or all of: scheme, hostname, path, query, and fragment;
- # see {URI syntax}[https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax].
- #
- # A Ruby {Gem::URI::Generic}[rdoc-ref:Gem::URI::Generic] object
- # represents an internet URI.
- # It provides, among others, methods
- # +scheme+, +hostname+, +path+, +query+, and +fragment+.
- #
- # === Schemes
- #
- # An internet \Gem::URI has
- # a {scheme}[https://en.wikipedia.org/wiki/List_of_URI_schemes].
- #
- # The two schemes supported in \Gem::Net::HTTP are <tt>'https'</tt> and <tt>'http'</tt>:
- #
- # uri.scheme # => "https"
- # Gem::URI('http://example.com').scheme # => "http"
- #
- # === Hostnames
- #
- # A hostname identifies a server (host) to which requests may be sent:
- #
- # hostname = uri.hostname # => "jsonplaceholder.typicode.com"
- # Gem::Net::HTTP.start(hostname) do |http|
- # # Some HTTP stuff.
- # end
- #
- # === Paths
- #
- # A host-specific path identifies a resource on the host:
- #
- # _uri = uri.dup
- # _uri.path = '/todos/1'
- # hostname = _uri.hostname
- # path = _uri.path
- # Gem::Net::HTTP.get(hostname, path)
- #
- # === Queries
- #
- # A host-specific query adds name/value pairs to the URI:
- #
- # _uri = uri.dup
- # params = {userId: 1, completed: false}
- # _uri.query = Gem::URI.encode_www_form(params)
- # _uri # => #<Gem::URI::HTTPS https://jsonplaceholder.typicode.com?userId=1&completed=false>
- # Gem::Net::HTTP.get(_uri)
- #
- # === Fragments
- #
- # A {URI fragment}[https://en.wikipedia.org/wiki/URI_fragment] has no effect
- # in \Gem::Net::HTTP;
- # the same data is returned, regardless of whether a fragment is included.
- #
- # == Request Headers
- #
- # Request headers may be used to pass additional information to the host,
- # similar to arguments passed in a method call;
- # each header is a name/value pair.
- #
- # Each of the \Gem::Net::HTTP methods that sends a request to the host
- # has optional argument +headers+,
- # where the headers are expressed as a hash of field-name/value pairs:
- #
- # headers = {Accept: 'application/json', Connection: 'Keep-Alive'}
- # Gem::Net::HTTP.get(uri, headers)
- #
- # See lists of both standard request fields and common request fields at
- # {Request Fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields].
- # A host may also accept other custom fields.
- #
- # == \HTTP Sessions
- #
- # A _session_ is a connection between a server (host) and a client that:
- #
- # - Is begun by instance method Gem::Net::HTTP#start.
- # - May contain any number of requests.
- # - Is ended by instance method Gem::Net::HTTP#finish.
- #
- # See example sessions at {Strategies}[rdoc-ref:Gem::Net::HTTP@Strategies].
- #
- # === Session Using \Gem::Net::HTTP.start
- #
- # If you have many requests to make to a single host (and port),
- # consider using singleton method Gem::Net::HTTP.start with a block;
- # the method handles the session automatically by:
- #
- # - Calling #start before block execution.
- # - Executing the block.
- # - Calling #finish after block execution.
- #
- # In the block, you can use these instance methods,
- # each of which that sends a single request:
- #
- # - {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods]:
- #
- # - #get, #request_get: GET.
- # - #head, #request_head: HEAD.
- # - #post, #request_post: POST.
- # - #delete: DELETE.
- # - #options: OPTIONS.
- # - #trace: TRACE.
- # - #patch: PATCH.
- #
- # - {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
- #
- # - #copy: COPY.
- # - #lock: LOCK.
- # - #mkcol: MKCOL.
- # - #move: MOVE.
- # - #propfind: PROPFIND.
- # - #proppatch: PROPPATCH.
- # - #unlock: UNLOCK.
- #
- # === Session Using \Gem::Net::HTTP.start and \Gem::Net::HTTP.finish
- #
- # You can manage a session manually using methods #start and #finish:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.start
- # http.get('/todos/1')
- # http.get('/todos/2')
- # http.delete('/posts/1')
- # http.finish # Needed to free resources.
- #
- # === Single-Request Session
- #
- # Certain convenience methods automatically handle a session by:
- #
- # - Creating an \HTTP object
- # - Starting a session.
- # - Sending a single request.
- # - Finishing the session.
- # - Destroying the object.
- #
- # Such methods that send GET requests:
- #
- # - ::get: Returns the string response body.
- # - ::get_print: Writes the string response body to $stdout.
- # - ::get_response: Returns a Gem::Net::HTTPResponse object.
- #
- # Such methods that send POST requests:
- #
- # - ::post: Posts data to the host.
- # - ::post_form: Posts form data to the host.
- #
- # == \HTTP Requests and Responses
- #
- # Many of the methods above are convenience methods,
- # each of which sends a request and returns a string
- # without directly using \Gem::Net::HTTPRequest and \Gem::Net::HTTPResponse objects.
- #
- # You can, however, directly create a request object, send the request,
- # and retrieve the response object; see:
- #
- # - Gem::Net::HTTPRequest.
- # - Gem::Net::HTTPResponse.
- #
- # == Following Redirection
- #
- # Each returned response is an instance of a subclass of Gem::Net::HTTPResponse.
- # See the {response class hierarchy}[rdoc-ref:Gem::Net::HTTPResponse@Response+Subclasses].
- #
- # In particular, class Gem::Net::HTTPRedirection is the parent
- # of all redirection classes.
- # This allows you to craft a case statement to handle redirections properly:
- #
- # def fetch(uri, limit = 10)
- # # You should choose a better exception.
- # raise ArgumentError, 'Too many HTTP redirects' if limit == 0
- #
- # res = Gem::Net::HTTP.get_response(Gem::URI(uri))
- # case res
- # when Gem::Net::HTTPSuccess # Any success class.
- # res
- # when Gem::Net::HTTPRedirection # Any redirection class.
- # location = res['Location']
- # warn "Redirected to #{location}"
- # fetch(location, limit - 1)
- # else # Any other class.
- # res.value
- # end
- # end
- #
- # fetch(uri)
- #
- # == Basic Authentication
- #
- # Basic authentication is performed according to
- # {RFC2617}[http://www.ietf.org/rfc/rfc2617.txt]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.basic_auth('user', 'pass')
- # res = Gem::Net::HTTP.start(hostname) do |http|
- # http.request(req)
- # end
- #
- # == Streaming Response Bodies
- #
- # By default \Gem::Net::HTTP reads an entire response into memory. If you are
- # handling large files or wish to implement a progress bar you can instead
- # stream the body directly to an IO.
- #
- # Gem::Net::HTTP.start(hostname) do |http|
- # req = Gem::Net::HTTP::Get.new(uri)
- # http.request(req) do |res|
- # open('t.tmp', 'w') do |f|
- # res.read_body do |chunk|
- # f.write chunk
- # end
- # end
- # end
- # end
- #
- # == HTTPS
- #
- # HTTPS is enabled for an \HTTP connection by Gem::Net::HTTP#use_ssl=:
- #
- # Gem::Net::HTTP.start(hostname, :use_ssl => true) do |http|
- # req = Gem::Net::HTTP::Get.new(uri)
- # res = http.request(req)
- # end
- #
- # Or if you simply want to make a GET request, you may pass in a URI
- # object that has an \HTTPS URL. \Gem::Net::HTTP automatically turns on TLS
- # verification if the URI object has a 'https' :URI scheme:
- #
- # uri # => #<Gem::URI::HTTPS https://jsonplaceholder.typicode.com/>
- # Gem::Net::HTTP.get(uri)
- #
- # == Proxy Server
- #
- # An \HTTP object can have
- # a {proxy server}[https://en.wikipedia.org/wiki/Proxy_server].
- #
- # You can create an \HTTP object with a proxy server
- # using method Gem::Net::HTTP.new or method Gem::Net::HTTP.start.
- #
- # The proxy may be defined either by argument +p_addr+
- # or by environment variable <tt>'http_proxy'</tt>.
- #
- # === Proxy Using Argument +p_addr+ as a \String
- #
- # When argument +p_addr+ is a string hostname,
- # the returned +http+ has the given host as its proxy:
- #
- # http = Gem::Net::HTTP.new(hostname, nil, 'proxy.example')
- # http.proxy? # => true
- # http.proxy_from_env? # => false
- # http.proxy_address # => "proxy.example"
- # # These use default values.
- # http.proxy_port # => 80
- # http.proxy_user # => nil
- # http.proxy_pass # => nil
- #
- # The port, username, and password for the proxy may also be given:
- #
- # http = Gem::Net::HTTP.new(hostname, nil, 'proxy.example', 8000, 'pname', 'ppass')
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.proxy? # => true
- # http.proxy_from_env? # => false
- # http.proxy_address # => "proxy.example"
- # http.proxy_port # => 8000
- # http.proxy_user # => "pname"
- # http.proxy_pass # => "ppass"
- #
- # === Proxy Using '<tt>ENV['http_proxy']</tt>'
- #
- # When environment variable <tt>'http_proxy'</tt>
- # is set to a \Gem::URI string,
- # the returned +http+ will have the server at that URI as its proxy;
- # note that the \Gem::URI string must have a protocol
- # such as <tt>'http'</tt> or <tt>'https'</tt>:
- #
- # ENV['http_proxy'] = 'http://example.com'
- # http = Gem::Net::HTTP.new(hostname)
- # http.proxy? # => true
- # http.proxy_from_env? # => true
- # http.proxy_address # => "example.com"
- # # These use default values.
- # http.proxy_port # => 80
- # http.proxy_user # => nil
- # http.proxy_pass # => nil
- #
- # The \Gem::URI string may include proxy username, password, and port number:
- #
- # ENV['http_proxy'] = 'http://pname:ppass@example.com:8000'
- # http = Gem::Net::HTTP.new(hostname)
- # http.proxy? # => true
- # http.proxy_from_env? # => true
- # http.proxy_address # => "example.com"
- # http.proxy_port # => 8000
- # http.proxy_user # => "pname"
- # http.proxy_pass # => "ppass"
- #
- # === Filtering Proxies
- #
- # With method Gem::Net::HTTP.new (but not Gem::Net::HTTP.start),
- # you can use argument +p_no_proxy+ to filter proxies:
- #
- # - Reject a certain address:
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example')
- # http.proxy_address # => nil
- #
- # - Reject certain domains or subdomains:
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'my.proxy.example', 8000, 'pname', 'ppass', 'proxy.example')
- # http.proxy_address # => nil
- #
- # - Reject certain addresses and port combinations:
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:1234')
- # http.proxy_address # => "proxy.example"
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:8000')
- # http.proxy_address # => nil
- #
- # - Reject a list of the types above delimited using a comma:
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000')
- # http.proxy_address # => nil
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'my.proxy', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000')
- # http.proxy_address # => nil
- #
- # == Compression and Decompression
- #
- # \Gem::Net::HTTP does not compress the body of a request before sending.
- #
- # By default, \Gem::Net::HTTP adds header <tt>'Accept-Encoding'</tt>
- # to a new {request object}[rdoc-ref:Gem::Net::HTTPRequest]:
- #
- # Gem::Net::HTTP::Get.new(uri)['Accept-Encoding']
- # # => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
- #
- # This requests the server to zip-encode the response body if there is one;
- # the server is not required to do so.
- #
- # \Gem::Net::HTTP does not automatically decompress a response body
- # if the response has header <tt>'Content-Range'</tt>.
- #
- # Otherwise decompression (or not) depends on the value of header
- # {Content-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-encoding-response-header]:
- #
- # - <tt>'deflate'</tt>, <tt>'gzip'</tt>, or <tt>'x-gzip'</tt>:
- # decompresses the body and deletes the header.
- # - <tt>'none'</tt> or <tt>'identity'</tt>:
- # does not decompress the body, but deletes the header.
- # - Any other value:
- # leaves the body and header unchanged.
- #
- # == What's Here
- #
- # This is a categorized summary of methods and attributes.
- #
- # === \Gem::Net::HTTP Objects
- #
- # - {::new}[rdoc-ref:Gem::Net::HTTP.new]:
- # Creates a new instance.
- # - {#inspect}[rdoc-ref:Gem::Net::HTTP#inspect]:
- # Returns a string representation of +self+.
- #
- # === Sessions
- #
- # - {::start}[rdoc-ref:Gem::Net::HTTP.start]:
- # Begins a new session in a new \Gem::Net::HTTP object.
- # - {#started?}[rdoc-ref:Gem::Net::HTTP#started?]
- # (aliased as {#active?}[rdoc-ref:Gem::Net::HTTP#active?]):
- # Returns whether in a session.
- # - {#finish}[rdoc-ref:Gem::Net::HTTP#finish]:
- # Ends an active session.
- # - {#start}[rdoc-ref:Gem::Net::HTTP#start]:
- # Begins a new session in an existing \Gem::Net::HTTP object (+self+).
- #
- # === Connections
- #
- # - {:continue_timeout}[rdoc-ref:Gem::Net::HTTP#continue_timeout]:
- # Returns the continue timeout.
- # - {#continue_timeout=}[rdoc-ref:Gem::Net::HTTP#continue_timeout=]:
- # Sets the continue timeout seconds.
- # - {:keep_alive_timeout}[rdoc-ref:Gem::Net::HTTP#keep_alive_timeout]:
- # Returns the keep-alive timeout.
- # - {:keep_alive_timeout=}[rdoc-ref:Gem::Net::HTTP#keep_alive_timeout=]:
- # Sets the keep-alive timeout.
- # - {:max_retries}[rdoc-ref:Gem::Net::HTTP#max_retries]:
- # Returns the maximum retries.
- # - {#max_retries=}[rdoc-ref:Gem::Net::HTTP#max_retries=]:
- # Sets the maximum retries.
- # - {:open_timeout}[rdoc-ref:Gem::Net::HTTP#open_timeout]:
- # Returns the open timeout.
- # - {:open_timeout=}[rdoc-ref:Gem::Net::HTTP#open_timeout=]:
- # Sets the open timeout.
- # - {:read_timeout}[rdoc-ref:Gem::Net::HTTP#read_timeout]:
- # Returns the open timeout.
- # - {:read_timeout=}[rdoc-ref:Gem::Net::HTTP#read_timeout=]:
- # Sets the read timeout.
- # - {:ssl_timeout}[rdoc-ref:Gem::Net::HTTP#ssl_timeout]:
- # Returns the ssl timeout.
- # - {:ssl_timeout=}[rdoc-ref:Gem::Net::HTTP#ssl_timeout=]:
- # Sets the ssl timeout.
- # - {:write_timeout}[rdoc-ref:Gem::Net::HTTP#write_timeout]:
- # Returns the write timeout.
- # - {write_timeout=}[rdoc-ref:Gem::Net::HTTP#write_timeout=]:
- # Sets the write timeout.
- #
- # === Requests
- #
- # - {::get}[rdoc-ref:Gem::Net::HTTP.get]:
- # Sends a GET request and returns the string response body.
- # - {::get_print}[rdoc-ref:Gem::Net::HTTP.get_print]:
- # Sends a GET request and write the string response body to $stdout.
- # - {::get_response}[rdoc-ref:Gem::Net::HTTP.get_response]:
- # Sends a GET request and returns a response object.
- # - {::post_form}[rdoc-ref:Gem::Net::HTTP.post_form]:
- # Sends a POST request with form data and returns a response object.
- # - {::post}[rdoc-ref:Gem::Net::HTTP.post]:
- # Sends a POST request with data and returns a response object.
- # - {#copy}[rdoc-ref:Gem::Net::HTTP#copy]:
- # Sends a COPY request and returns a response object.
- # - {#delete}[rdoc-ref:Gem::Net::HTTP#delete]:
- # Sends a DELETE request and returns a response object.
- # - {#get}[rdoc-ref:Gem::Net::HTTP#get]:
- # Sends a GET request and returns a response object.
- # - {#head}[rdoc-ref:Gem::Net::HTTP#head]:
- # Sends a HEAD request and returns a response object.
- # - {#lock}[rdoc-ref:Gem::Net::HTTP#lock]:
- # Sends a LOCK request and returns a response object.
- # - {#mkcol}[rdoc-ref:Gem::Net::HTTP#mkcol]:
- # Sends a MKCOL request and returns a response object.
- # - {#move}[rdoc-ref:Gem::Net::HTTP#move]:
- # Sends a MOVE request and returns a response object.
- # - {#options}[rdoc-ref:Gem::Net::HTTP#options]:
- # Sends a OPTIONS request and returns a response object.
- # - {#patch}[rdoc-ref:Gem::Net::HTTP#patch]:
- # Sends a PATCH request and returns a response object.
- # - {#post}[rdoc-ref:Gem::Net::HTTP#post]:
- # Sends a POST request and returns a response object.
- # - {#propfind}[rdoc-ref:Gem::Net::HTTP#propfind]:
- # Sends a PROPFIND request and returns a response object.
- # - {#proppatch}[rdoc-ref:Gem::Net::HTTP#proppatch]:
- # Sends a PROPPATCH request and returns a response object.
- # - {#put}[rdoc-ref:Gem::Net::HTTP#put]:
- # Sends a PUT request and returns a response object.
- # - {#request}[rdoc-ref:Gem::Net::HTTP#request]:
- # Sends a request and returns a response object.
- # - {#request_get}[rdoc-ref:Gem::Net::HTTP#request_get]
- # (aliased as {#get2}[rdoc-ref:Gem::Net::HTTP#get2]):
- # Sends a GET request and forms a response object;
- # if a block given, calls the block with the object,
- # otherwise returns the object.
- # - {#request_head}[rdoc-ref:Gem::Net::HTTP#request_head]
- # (aliased as {#head2}[rdoc-ref:Gem::Net::HTTP#head2]):
- # Sends a HEAD request and forms a response object;
- # if a block given, calls the block with the object,
- # otherwise returns the object.
- # - {#request_post}[rdoc-ref:Gem::Net::HTTP#request_post]
- # (aliased as {#post2}[rdoc-ref:Gem::Net::HTTP#post2]):
- # Sends a POST request and forms a response object;
- # if a block given, calls the block with the object,
- # otherwise returns the object.
- # - {#send_request}[rdoc-ref:Gem::Net::HTTP#send_request]:
- # Sends a request and returns a response object.
- # - {#trace}[rdoc-ref:Gem::Net::HTTP#trace]:
- # Sends a TRACE request and returns a response object.
- # - {#unlock}[rdoc-ref:Gem::Net::HTTP#unlock]:
- # Sends an UNLOCK request and returns a response object.
- #
- # === Responses
- #
- # - {:close_on_empty_response}[rdoc-ref:Gem::Net::HTTP#close_on_empty_response]:
- # Returns whether to close connection on empty response.
- # - {:close_on_empty_response=}[rdoc-ref:Gem::Net::HTTP#close_on_empty_response=]:
- # Sets whether to close connection on empty response.
- # - {:ignore_eof}[rdoc-ref:Gem::Net::HTTP#ignore_eof]:
- # Returns whether to ignore end-of-file when reading a response body
- # with <tt>Content-Length</tt> headers.
- # - {:ignore_eof=}[rdoc-ref:Gem::Net::HTTP#ignore_eof=]:
- # Sets whether to ignore end-of-file when reading a response body
- # with <tt>Content-Length</tt> headers.
- # - {:response_body_encoding}[rdoc-ref:Gem::Net::HTTP#response_body_encoding]:
- # Returns the encoding to use for the response body.
- # - {#response_body_encoding=}[rdoc-ref:Gem::Net::HTTP#response_body_encoding=]:
- # Sets the response body encoding.
- #
- # === Proxies
- #
- # - {:proxy_address}[rdoc-ref:Gem::Net::HTTP#proxy_address]:
- # Returns the proxy address.
- # - {:proxy_address=}[rdoc-ref:Gem::Net::HTTP#proxy_address=]:
- # Sets the proxy address.
- # - {::proxy_class?}[rdoc-ref:Gem::Net::HTTP.proxy_class?]:
- # Returns whether +self+ is a proxy class.
- # - {#proxy?}[rdoc-ref:Gem::Net::HTTP#proxy?]:
- # Returns whether +self+ has a proxy.
- # - {#proxy_address}[rdoc-ref:Gem::Net::HTTP#proxy_address]
- # (aliased as {#proxyaddr}[rdoc-ref:Gem::Net::HTTP#proxyaddr]):
- # Returns the proxy address.
- # - {#proxy_from_env?}[rdoc-ref:Gem::Net::HTTP#proxy_from_env?]:
- # Returns whether the proxy is taken from an environment variable.
- # - {:proxy_from_env=}[rdoc-ref:Gem::Net::HTTP#proxy_from_env=]:
- # Sets whether the proxy is to be taken from an environment variable.
- # - {:proxy_pass}[rdoc-ref:Gem::Net::HTTP#proxy_pass]:
- # Returns the proxy password.
- # - {:proxy_pass=}[rdoc-ref:Gem::Net::HTTP#proxy_pass=]:
- # Sets the proxy password.
- # - {:proxy_port}[rdoc-ref:Gem::Net::HTTP#proxy_port]:
- # Returns the proxy port.
- # - {:proxy_port=}[rdoc-ref:Gem::Net::HTTP#proxy_port=]:
- # Sets the proxy port.
- # - {#proxy_user}[rdoc-ref:Gem::Net::HTTP#proxy_user]:
- # Returns the proxy user name.
- # - {:proxy_user=}[rdoc-ref:Gem::Net::HTTP#proxy_user=]:
- # Sets the proxy user.
- #
- # === Security
- #
- # - {:ca_file}[rdoc-ref:Gem::Net::HTTP#ca_file]:
- # Returns the path to a CA certification file.
- # - {:ca_file=}[rdoc-ref:Gem::Net::HTTP#ca_file=]:
- # Sets the path to a CA certification file.
- # - {:ca_path}[rdoc-ref:Gem::Net::HTTP#ca_path]:
- # Returns the path of to CA directory containing certification files.
- # - {:ca_path=}[rdoc-ref:Gem::Net::HTTP#ca_path=]:
- # Sets the path of to CA directory containing certification files.
- # - {:cert}[rdoc-ref:Gem::Net::HTTP#cert]:
- # Returns the OpenSSL::X509::Certificate object to be used for client certification.
- # - {:cert=}[rdoc-ref:Gem::Net::HTTP#cert=]:
- # Sets the OpenSSL::X509::Certificate object to be used for client certification.
- # - {:cert_store}[rdoc-ref:Gem::Net::HTTP#cert_store]:
- # Returns the X509::Store to be used for verifying peer certificate.
- # - {:cert_store=}[rdoc-ref:Gem::Net::HTTP#cert_store=]:
- # Sets the X509::Store to be used for verifying peer certificate.
- # - {:ciphers}[rdoc-ref:Gem::Net::HTTP#ciphers]:
- # Returns the available SSL ciphers.
- # - {:ciphers=}[rdoc-ref:Gem::Net::HTTP#ciphers=]:
- # Sets the available SSL ciphers.
- # - {:extra_chain_cert}[rdoc-ref:Gem::Net::HTTP#extra_chain_cert]:
- # Returns the extra X509 certificates to be added to the certificate chain.
- # - {:extra_chain_cert=}[rdoc-ref:Gem::Net::HTTP#extra_chain_cert=]:
- # Sets the extra X509 certificates to be added to the certificate chain.
- # - {:key}[rdoc-ref:Gem::Net::HTTP#key]:
- # Returns the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
- # - {:key=}[rdoc-ref:Gem::Net::HTTP#key=]:
- # Sets the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
- # - {:max_version}[rdoc-ref:Gem::Net::HTTP#max_version]:
- # Returns the maximum SSL version.
- # - {:max_version=}[rdoc-ref:Gem::Net::HTTP#max_version=]:
- # Sets the maximum SSL version.
- # - {:min_version}[rdoc-ref:Gem::Net::HTTP#min_version]:
- # Returns the minimum SSL version.
- # - {:min_version=}[rdoc-ref:Gem::Net::HTTP#min_version=]:
- # Sets the minimum SSL version.
- # - {#peer_cert}[rdoc-ref:Gem::Net::HTTP#peer_cert]:
- # Returns the X509 certificate chain for the session's socket peer.
- # - {:ssl_version}[rdoc-ref:Gem::Net::HTTP#ssl_version]:
- # Returns the SSL version.
- # - {:ssl_version=}[rdoc-ref:Gem::Net::HTTP#ssl_version=]:
- # Sets the SSL version.
- # - {#use_ssl=}[rdoc-ref:Gem::Net::HTTP#use_ssl=]:
- # Sets whether a new session is to use Transport Layer Security.
- # - {#use_ssl?}[rdoc-ref:Gem::Net::HTTP#use_ssl?]:
- # Returns whether +self+ uses SSL.
- # - {:verify_callback}[rdoc-ref:Gem::Net::HTTP#verify_callback]:
- # Returns the callback for the server certification verification.
- # - {:verify_callback=}[rdoc-ref:Gem::Net::HTTP#verify_callback=]:
- # Sets the callback for the server certification verification.
- # - {:verify_depth}[rdoc-ref:Gem::Net::HTTP#verify_depth]:
- # Returns the maximum depth for the certificate chain verification.
- # - {:verify_depth=}[rdoc-ref:Gem::Net::HTTP#verify_depth=]:
- # Sets the maximum depth for the certificate chain verification.
- # - {:verify_hostname}[rdoc-ref:Gem::Net::HTTP#verify_hostname]:
- # Returns the flags for server the certification verification at the beginning of the SSL/TLS session.
- # - {:verify_hostname=}[rdoc-ref:Gem::Net::HTTP#verify_hostname=]:
- # Sets he flags for server the certification verification at the beginning of the SSL/TLS session.
- # - {:verify_mode}[rdoc-ref:Gem::Net::HTTP#verify_mode]:
- # Returns the flags for server the certification verification at the beginning of the SSL/TLS session.
- # - {:verify_mode=}[rdoc-ref:Gem::Net::HTTP#verify_mode=]:
- # Sets the flags for server the certification verification at the beginning of the SSL/TLS session.
- #
- # === Addresses and Ports
- #
- # - {:address}[rdoc-ref:Gem::Net::HTTP#address]:
- # Returns the string host name or host IP.
- # - {::default_port}[rdoc-ref:Gem::Net::HTTP.default_port]:
- # Returns integer 80, the default port to use for HTTP requests.
- # - {::http_default_port}[rdoc-ref:Gem::Net::HTTP.http_default_port]:
- # Returns integer 80, the default port to use for HTTP requests.
- # - {::https_default_port}[rdoc-ref:Gem::Net::HTTP.https_default_port]:
- # Returns integer 443, the default port to use for HTTPS requests.
- # - {#ipaddr}[rdoc-ref:Gem::Net::HTTP#ipaddr]:
- # Returns the IP address for the connection.
- # - {#ipaddr=}[rdoc-ref:Gem::Net::HTTP#ipaddr=]:
- # Sets the IP address for the connection.
- # - {:local_host}[rdoc-ref:Gem::Net::HTTP#local_host]:
- # Returns the string local host used to establish the connection.
- # - {:local_host=}[rdoc-ref:Gem::Net::HTTP#local_host=]:
- # Sets the string local host used to establish the connection.
- # - {:local_port}[rdoc-ref:Gem::Net::HTTP#local_port]:
- # Returns the integer local port used to establish the connection.
- # - {:local_port=}[rdoc-ref:Gem::Net::HTTP#local_port=]:
- # Sets the integer local port used to establish the connection.
- # - {:port}[rdoc-ref:Gem::Net::HTTP#port]:
- # Returns the integer port number.
- #
- # === \HTTP Version
- #
- # - {::version_1_2?}[rdoc-ref:Gem::Net::HTTP.version_1_2?]
- # (aliased as {::is_version_1_2?}[rdoc-ref:Gem::Net::HTTP.is_version_1_2?]
- # and {::version_1_2}[rdoc-ref:Gem::Net::HTTP.version_1_2]):
- # Returns true; retained for compatibility.
- #
- # === Debugging
- #
- # - {#set_debug_output}[rdoc-ref:Gem::Net::HTTP#set_debug_output]:
- # Sets the output stream for debugging.
- #
- class HTTP < Protocol
-
- # :stopdoc:
- VERSION = "0.4.1"
- HTTPVersion = '1.1'
- begin
- require 'zlib'
- HAVE_ZLIB=true
- rescue LoadError
- HAVE_ZLIB=false
- end
- # :startdoc:
-
- # Returns +true+; retained for compatibility.
- def HTTP.version_1_2
- true
- end
-
- # Returns +true+; retained for compatibility.
- def HTTP.version_1_2?
- true
- end
-
- # Returns +false+; retained for compatibility.
- def HTTP.version_1_1? #:nodoc:
- false
- end
-
- class << HTTP
- alias is_version_1_1? version_1_1? #:nodoc:
- alias is_version_1_2? version_1_2? #:nodoc:
- end
-
- # :call-seq:
- # Gem::Net::HTTP.get_print(hostname, path, port = 80) -> nil
- # Gem::Net::HTTP:get_print(uri, headers = {}, port = uri.port) -> nil
- #
- # Like Gem::Net::HTTP.get, but writes the returned body to $stdout;
- # returns +nil+.
- def HTTP.get_print(uri_or_host, path_or_headers = nil, port = nil)
- get_response(uri_or_host, path_or_headers, port) {|res|
- res.read_body do |chunk|
- $stdout.print chunk
- end
- }
- nil
- end
-
- # :call-seq:
- # Gem::Net::HTTP.get(hostname, path, port = 80) -> body
- # Gem::Net::HTTP:get(uri, headers = {}, port = uri.port) -> body
- #
- # Sends a GET request and returns the \HTTP response body as a string.
- #
- # With string arguments +hostname+ and +path+:
- #
- # hostname = 'jsonplaceholder.typicode.com'
- # path = '/todos/1'
- # puts Gem::Net::HTTP.get(hostname, path)
- #
- # Output:
- #
- # {
- # "userId": 1,
- # "id": 1,
- # "title": "delectus aut autem",
- # "completed": false
- # }
- #
- # With URI object +uri+ and optional hash argument +headers+:
- #
- # uri = Gem::URI('https://jsonplaceholder.typicode.com/todos/1')
- # headers = {'Content-type' => 'application/json; charset=UTF-8'}
- # Gem::Net::HTTP.get(uri, headers)
- #
- # Related:
- #
- # - Gem::Net::HTTP::Get: request class for \HTTP method +GET+.
- # - Gem::Net::HTTP#get: convenience method for \HTTP method +GET+.
- #
- def HTTP.get(uri_or_host, path_or_headers = nil, port = nil)
- get_response(uri_or_host, path_or_headers, port).body
- end
-
- # :call-seq:
- # Gem::Net::HTTP.get_response(hostname, path, port = 80) -> http_response
- # Gem::Net::HTTP:get_response(uri, headers = {}, port = uri.port) -> http_response
- #
- # Like Gem::Net::HTTP.get, but returns a Gem::Net::HTTPResponse object
- # instead of the body string.
- def HTTP.get_response(uri_or_host, path_or_headers = nil, port = nil, &block)
- if path_or_headers && !path_or_headers.is_a?(Hash)
- host = uri_or_host
- path = path_or_headers
- new(host, port || HTTP.default_port).start {|http|
- return http.request_get(path, &block)
- }
- else
- uri = uri_or_host
- headers = path_or_headers
- start(uri.hostname, uri.port,
- :use_ssl => uri.scheme == 'https') {|http|
- return http.request_get(uri, headers, &block)
- }
- end
- end
-
- # Posts data to a host; returns a Gem::Net::HTTPResponse object.
- #
- # Argument +url+ must be a URL;
- # argument +data+ must be a string:
- #
- # _uri = uri.dup
- # _uri.path = '/posts'
- # data = '{"title": "foo", "body": "bar", "userId": 1}'
- # headers = {'content-type': 'application/json'}
- # res = Gem::Net::HTTP.post(_uri, data, headers) # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- # puts res.body
- #
- # Output:
- #
- # {
- # "title": "foo",
- # "body": "bar",
- # "userId": 1,
- # "id": 101
- # }
- #
- # Related:
- #
- # - Gem::Net::HTTP::Post: request class for \HTTP method +POST+.
- # - Gem::Net::HTTP#post: convenience method for \HTTP method +POST+.
- #
- def HTTP.post(url, data, header = nil)
- start(url.hostname, url.port,
- :use_ssl => url.scheme == 'https' ) {|http|
- http.post(url, data, header)
- }
- end
-
- # Posts data to a host; returns a Gem::Net::HTTPResponse object.
- #
- # Argument +url+ must be a URI;
- # argument +data+ must be a hash:
- #
- # _uri = uri.dup
- # _uri.path = '/posts'
- # data = {title: 'foo', body: 'bar', userId: 1}
- # res = Gem::Net::HTTP.post_form(_uri, data) # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- # puts res.body
- #
- # Output:
- #
- # {
- # "title": "foo",
- # "body": "bar",
- # "userId": "1",
- # "id": 101
- # }
- #
- def HTTP.post_form(url, params)
- req = Post.new(url)
- req.form_data = params
- req.basic_auth url.user, url.password if url.user
- start(url.hostname, url.port,
- :use_ssl => url.scheme == 'https' ) {|http|
- http.request(req)
- }
- end
-
- #
- # \HTTP session management
- #
-
- # Returns integer +80+, the default port to use for \HTTP requests:
- #
- # Gem::Net::HTTP.default_port # => 80
- #
- def HTTP.default_port
- http_default_port()
- end
-
- # Returns integer +80+, the default port to use for \HTTP requests:
- #
- # Gem::Net::HTTP.http_default_port # => 80
- #
- def HTTP.http_default_port
- 80
- end
-
- # Returns integer +443+, the default port to use for HTTPS requests:
- #
- # Gem::Net::HTTP.https_default_port # => 443
- #
- def HTTP.https_default_port
- 443
- end
-
- def HTTP.socket_type #:nodoc: obsolete
- BufferedIO
- end
-
- # :call-seq:
- # HTTP.start(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, opts) -> http
- # HTTP.start(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, opts) {|http| ... } -> object
- #
- # Creates a new \Gem::Net::HTTP object, +http+, via \Gem::Net::HTTP.new:
- #
- # - For arguments +address+ and +port+, see Gem::Net::HTTP.new.
- # - For proxy-defining arguments +p_addr+ through +p_pass+,
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- # - For argument +opts+, see below.
- #
- # With no block given:
- #
- # - Calls <tt>http.start</tt> with no block (see #start),
- # which opens a TCP connection and \HTTP session.
- # - Returns +http+.
- # - The caller should call #finish to close the session:
- #
- # http = Gem::Net::HTTP.start(hostname)
- # http.started? # => true
- # http.finish
- # http.started? # => false
- #
- # With a block given:
- #
- # - Calls <tt>http.start</tt> with the block (see #start), which:
- #
- # - Opens a TCP connection and \HTTP session.
- # - Calls the block,
- # which may make any number of requests to the host.
- # - Closes the \HTTP session and TCP connection on block exit.
- # - Returns the block's value +object+.
- #
- # - Returns +object+.
- #
- # Example:
- #
- # hostname = 'jsonplaceholder.typicode.com'
- # Gem::Net::HTTP.start(hostname) do |http|
- # puts http.get('/todos/1').body
- # puts http.get('/todos/2').body
- # end
- #
- # Output:
- #
- # {
- # "userId": 1,
- # "id": 1,
- # "title": "delectus aut autem",
- # "completed": false
- # }
- # {
- # "userId": 1,
- # "id": 2,
- # "title": "quis ut nam facilis et officia qui",
- # "completed": false
- # }
- #
- # If the last argument given is a hash, it is the +opts+ hash,
- # where each key is a method or accessor to be called,
- # and its value is the value to be set.
- #
- # The keys may include:
- #
- # - #ca_file
- # - #ca_path
- # - #cert
- # - #cert_store
- # - #ciphers
- # - #close_on_empty_response
- # - +ipaddr+ (calls #ipaddr=)
- # - #keep_alive_timeout
- # - #key
- # - #open_timeout
- # - #read_timeout
- # - #ssl_timeout
- # - #ssl_version
- # - +use_ssl+ (calls #use_ssl=)
- # - #verify_callback
- # - #verify_depth
- # - #verify_mode
- # - #write_timeout
- #
- # Note: If +port+ is +nil+ and <tt>opts[:use_ssl]</tt> is a truthy value,
- # the value passed to +new+ is Gem::Net::HTTP.https_default_port, not +port+.
- #
- def HTTP.start(address, *arg, &block) # :yield: +http+
- arg.pop if opt = Hash.try_convert(arg[-1])
- port, p_addr, p_port, p_user, p_pass = *arg
- p_addr = :ENV if arg.size < 2
- port = https_default_port if !port && opt && opt[:use_ssl]
- http = new(address, port, p_addr, p_port, p_user, p_pass)
- http.ipaddr = opt[:ipaddr] if opt && opt[:ipaddr]
-
- if opt
- if opt[:use_ssl]
- opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt)
- end
- http.methods.grep(/\A(\w+)=\z/) do |meth|
- key = $1.to_sym
- opt.key?(key) or next
- http.__send__(meth, opt[key])
- end
- end
-
- http.start(&block)
- end
-
- class << HTTP
- alias newobj new # :nodoc:
- end
-
- # Returns a new \Gem::Net::HTTP object +http+
- # (but does not open a TCP connection or \HTTP session).
- #
- # With only string argument +address+ given
- # (and <tt>ENV['http_proxy']</tt> undefined or +nil+),
- # the returned +http+:
- #
- # - Has the given address.
- # - Has the default port number, Gem::Net::HTTP.default_port (80).
- # - Has no proxy.
- #
- # Example:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.address # => "jsonplaceholder.typicode.com"
- # http.port # => 80
- # http.proxy? # => false
- #
- # With integer argument +port+ also given,
- # the returned +http+ has the given port:
- #
- # http = Gem::Net::HTTP.new(hostname, 8000)
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:8000 open=false>
- # http.port # => 8000
- #
- # For proxy-defining arguments +p_addr+ through +p_no_proxy+,
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- #
- def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil)
- http = super address, port
-
- if proxy_class? then # from Gem::Net::HTTP::Proxy()
- http.proxy_from_env = @proxy_from_env
- http.proxy_address = @proxy_address
- http.proxy_port = @proxy_port
- http.proxy_user = @proxy_user
- http.proxy_pass = @proxy_pass
- elsif p_addr == :ENV then
- http.proxy_from_env = true
- else
- if p_addr && p_no_proxy && !Gem::URI::Generic.use_proxy?(address, address, port, p_no_proxy)
- p_addr = nil
- p_port = nil
- end
- http.proxy_address = p_addr
- http.proxy_port = p_port || default_port
- http.proxy_user = p_user
- http.proxy_pass = p_pass
- end
-
- http
- end
-
- # Creates a new \Gem::Net::HTTP object for the specified server address,
- # without opening the TCP connection or initializing the \HTTP session.
- # The +address+ should be a DNS hostname or IP address.
- def initialize(address, port = nil) # :nodoc:
- @address = address
- @port = (port || HTTP.default_port)
- @ipaddr = nil
- @local_host = nil
- @local_port = nil
- @curr_http_version = HTTPVersion
- @keep_alive_timeout = 2
- @last_communicated = nil
- @close_on_empty_response = false
- @socket = nil
- @started = false
- @open_timeout = 60
- @read_timeout = 60
- @write_timeout = 60
- @continue_timeout = nil
- @max_retries = 1
- @debug_output = nil
- @response_body_encoding = false
- @ignore_eof = true
-
- @proxy_from_env = false
- @proxy_uri = nil
- @proxy_address = nil
- @proxy_port = nil
- @proxy_user = nil
- @proxy_pass = nil
-
- @use_ssl = false
- @ssl_context = nil
- @ssl_session = nil
- @sspi_enabled = false
- SSL_IVNAMES.each do |ivname|
- instance_variable_set ivname, nil
- end
- end
-
- # Returns a string representation of +self+:
- #
- # Gem::Net::HTTP.new(hostname).inspect
- # # => "#<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>"
- #
- def inspect
- "#<#{self.class} #{@address}:#{@port} open=#{started?}>"
- end
-
- # *WARNING* This method opens a serious security hole.
- # Never use this method in production code.
- #
- # Sets the output stream for debugging:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # File.open('t.tmp', 'w') do |file|
- # http.set_debug_output(file)
- # http.start
- # http.get('/nosuch/1')
- # http.finish
- # end
- # puts File.read('t.tmp')
- #
- # Output:
- #
- # opening connection to jsonplaceholder.typicode.com:80...
- # opened
- # <- "GET /nosuch/1 HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: jsonplaceholder.typicode.com\r\n\r\n"
- # -> "HTTP/1.1 404 Not Found\r\n"
- # -> "Date: Mon, 12 Dec 2022 21:14:11 GMT\r\n"
- # -> "Content-Type: application/json; charset=utf-8\r\n"
- # -> "Content-Length: 2\r\n"
- # -> "Connection: keep-alive\r\n"
- # -> "X-Powered-By: Express\r\n"
- # -> "X-Ratelimit-Limit: 1000\r\n"
- # -> "X-Ratelimit-Remaining: 999\r\n"
- # -> "X-Ratelimit-Reset: 1670879660\r\n"
- # -> "Vary: Origin, Accept-Encoding\r\n"
- # -> "Access-Control-Allow-Credentials: true\r\n"
- # -> "Cache-Control: max-age=43200\r\n"
- # -> "Pragma: no-cache\r\n"
- # -> "Expires: -1\r\n"
- # -> "X-Content-Type-Options: nosniff\r\n"
- # -> "Etag: W/\"2-vyGp6PvFo4RvsFtPoIWeCReyIC8\"\r\n"
- # -> "Via: 1.1 vegur\r\n"
- # -> "CF-Cache-Status: MISS\r\n"
- # -> "Server-Timing: cf-q-config;dur=1.3000000762986e-05\r\n"
- # -> "Report-To: {\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=yOr40jo%2BwS1KHzhTlVpl54beJ5Wx2FcG4gGV0XVrh3X9OlR5q4drUn2dkt5DGO4GDcE%2BVXT7CNgJvGs%2BZleIyMu8CLieFiDIvOviOY3EhHg94m0ZNZgrEdpKD0S85S507l1vsEwEHkoTm%2Ff19SiO\"}],\"group\":\"cf-nel\",\"max_age\":604800}\r\n"
- # -> "NEL: {\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}\r\n"
- # -> "Server: cloudflare\r\n"
- # -> "CF-RAY: 778977dc484ce591-DFW\r\n"
- # -> "alt-svc: h3=\":443\"; ma=86400, h3-29=\":443\"; ma=86400\r\n"
- # -> "\r\n"
- # reading 2 bytes...
- # -> "{}"
- # read 2 bytes
- # Conn keep-alive
- #
- def set_debug_output(output)
- warn 'Gem::Net::HTTP#set_debug_output called after HTTP started', uplevel: 1 if started?
- @debug_output = output
- end
-
- # Returns the string host name or host IP given as argument +address+ in ::new.
- attr_reader :address
-
- # Returns the integer port number given as argument +port+ in ::new.
- attr_reader :port
-
- # Sets or returns the string local host used to establish the connection;
- # initially +nil+.
- attr_accessor :local_host
-
- # Sets or returns the integer local port used to establish the connection;
- # initially +nil+.
- attr_accessor :local_port
-
- # Returns the encoding to use for the response body;
- # see #response_body_encoding=.
- attr_reader :response_body_encoding
-
- # Sets the encoding to be used for the response body;
- # returns the encoding.
- #
- # The given +value+ may be:
- #
- # - An Encoding object.
- # - The name of an encoding.
- # - An alias for an encoding name.
- #
- # See {Encoding}[rdoc-ref:Encoding].
- #
- # Examples:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.response_body_encoding = Encoding::US_ASCII # => #<Encoding:US-ASCII>
- # http.response_body_encoding = 'US-ASCII' # => "US-ASCII"
- # http.response_body_encoding = 'ASCII' # => "ASCII"
- #
- def response_body_encoding=(value)
- value = Encoding.find(value) if value.is_a?(String)
- @response_body_encoding = value
- end
-
- # Sets whether to determine the proxy from environment variable
- # '<tt>ENV['http_proxy']</tt>';
- # see {Proxy Using ENV['http_proxy']}[rdoc-ref:Gem::Net::HTTP@Proxy+Using+-27ENV-5B-27http_proxy-27-5D-27].
- attr_writer :proxy_from_env
-
- # Sets the proxy address;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- attr_writer :proxy_address
-
- # Sets the proxy port;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- attr_writer :proxy_port
-
- # Sets the proxy user;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- attr_writer :proxy_user
-
- # Sets the proxy password;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- attr_writer :proxy_pass
-
- # Returns the IP address for the connection.
- #
- # If the session has not been started,
- # returns the value set by #ipaddr=,
- # or +nil+ if it has not been set:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.ipaddr # => nil
- # http.ipaddr = '172.67.155.76'
- # http.ipaddr # => "172.67.155.76"
- #
- # If the session has been started,
- # returns the IP address from the socket:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.start
- # http.ipaddr # => "172.67.155.76"
- # http.finish
- #
- def ipaddr
- started? ? @socket.io.peeraddr[3] : @ipaddr
- end
-
- # Sets the IP address for the connection:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.ipaddr # => nil
- # http.ipaddr = '172.67.155.76'
- # http.ipaddr # => "172.67.155.76"
- #
- # The IP address may not be set if the session has been started.
- def ipaddr=(addr)
- raise IOError, "ipaddr value changed, but session already started" if started?
- @ipaddr = addr
- end
-
- # Sets or returns the numeric (\Integer or \Float) number of seconds
- # to wait for a connection to open;
- # initially 60.
- # If the connection is not made in the given interval,
- # an exception is raised.
- attr_accessor :open_timeout
-
- # Returns the numeric (\Integer or \Float) number of seconds
- # to wait for one block to be read (via one read(2) call);
- # see #read_timeout=.
- attr_reader :read_timeout
-
- # Returns the numeric (\Integer or \Float) number of seconds
- # to wait for one block to be written (via one write(2) call);
- # see #write_timeout=.
- attr_reader :write_timeout
-
- # Sets the maximum number of times to retry an idempotent request in case of
- # \Gem::Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET,
- # Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL::SSLError,
- # Gem::Timeout::Error.
- # The initial value is 1.
- #
- # Argument +retries+ must be a non-negative numeric value:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.max_retries = 2 # => 2
- # http.max_retries # => 2
- #
- def max_retries=(retries)
- retries = retries.to_int
- if retries < 0
- raise ArgumentError, 'max_retries should be non-negative integer number'
- end
- @max_retries = retries
- end
-
- # Returns the maximum number of times to retry an idempotent request;
- # see #max_retries=.
- attr_reader :max_retries
-
- # Sets the read timeout, in seconds, for +self+ to integer +sec+;
- # the initial value is 60.
- #
- # Argument +sec+ must be a non-negative numeric value:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.read_timeout # => 60
- # http.get('/todos/1') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- # http.read_timeout = 0
- # http.get('/todos/1') # Raises Gem::Net::ReadTimeout.
- #
- def read_timeout=(sec)
- @socket.read_timeout = sec if @socket
- @read_timeout = sec
- end
-
- # Sets the write timeout, in seconds, for +self+ to integer +sec+;
- # the initial value is 60.
- #
- # Argument +sec+ must be a non-negative numeric value:
- #
- # _uri = uri.dup
- # _uri.path = '/posts'
- # body = 'bar' * 200000
- # data = <<EOF
- # {"title": "foo", "body": "#{body}", "userId": "1"}
- # EOF
- # headers = {'content-type': 'application/json'}
- # http = Gem::Net::HTTP.new(hostname)
- # http.write_timeout # => 60
- # http.post(_uri.path, data, headers)
- # # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- # http.write_timeout = 0
- # http.post(_uri.path, data, headers) # Raises Gem::Net::WriteTimeout.
- #
- def write_timeout=(sec)
- @socket.write_timeout = sec if @socket
- @write_timeout = sec
- end
-
- # Returns the continue timeout value;
- # see continue_timeout=.
- attr_reader :continue_timeout
-
- # Sets the continue timeout value,
- # which is the number of seconds to wait for an expected 100 Continue response.
- # If the \HTTP object does not receive a response in this many seconds
- # it sends the request body.
- def continue_timeout=(sec)
- @socket.continue_timeout = sec if @socket
- @continue_timeout = sec
- end
-
- # Sets or returns the numeric (\Integer or \Float) number of seconds
- # to keep the connection open after a request is sent;
- # initially 2.
- # If a new request is made during the given interval,
- # the still-open connection is used;
- # otherwise the connection will have been closed
- # and a new connection is opened.
- attr_accessor :keep_alive_timeout
-
- # Sets or returns whether to ignore end-of-file when reading a response body
- # with <tt>Content-Length</tt> headers;
- # initially +true+.
- attr_accessor :ignore_eof
-
- # Returns +true+ if the \HTTP session has been started:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.started? # => false
- # http.start
- # http.started? # => true
- # http.finish # => nil
- # http.started? # => false
- #
- # Gem::Net::HTTP.start(hostname) do |http|
- # http.started?
- # end # => true
- # http.started? # => false
- #
- def started?
- @started
- end
-
- alias active? started? #:nodoc: obsolete
-
- # Sets or returns whether to close the connection when the response is empty;
- # initially +false+.
- attr_accessor :close_on_empty_response
-
- # Returns +true+ if +self+ uses SSL, +false+ otherwise.
- # See Gem::Net::HTTP#use_ssl=.
- def use_ssl?
- @use_ssl
- end
-
- # Sets whether a new session is to use
- # {Transport Layer Security}[https://en.wikipedia.org/wiki/Transport_Layer_Security]:
- #
- # Raises IOError if attempting to change during a session.
- #
- # Raises OpenSSL::SSL::SSLError if the port is not an HTTPS port.
- def use_ssl=(flag)
- flag = flag ? true : false
- if started? and @use_ssl != flag
- raise IOError, "use_ssl value changed, but session already started"
- end
- @use_ssl = flag
- end
-
- SSL_IVNAMES = [
- :@ca_file,
- :@ca_path,
- :@cert,
- :@cert_store,
- :@ciphers,
- :@extra_chain_cert,
- :@key,
- :@ssl_timeout,
- :@ssl_version,
- :@min_version,
- :@max_version,
- :@verify_callback,
- :@verify_depth,
- :@verify_mode,
- :@verify_hostname,
- ] # :nodoc:
- SSL_ATTRIBUTES = [
- :ca_file,
- :ca_path,
- :cert,
- :cert_store,
- :ciphers,
- :extra_chain_cert,
- :key,
- :ssl_timeout,
- :ssl_version,
- :min_version,
- :max_version,
- :verify_callback,
- :verify_depth,
- :verify_mode,
- :verify_hostname,
- ] # :nodoc:
-
- # Sets or returns the path to a CA certification file in PEM format.
- attr_accessor :ca_file
-
- # Sets or returns the path of to CA directory
- # containing certification files in PEM format.
- attr_accessor :ca_path
-
- # Sets or returns the OpenSSL::X509::Certificate object
- # to be used for client certification.
- attr_accessor :cert
-
- # Sets or returns the X509::Store to be used for verifying peer certificate.
- attr_accessor :cert_store
-
- # Sets or returns the available SSL ciphers.
- # See {OpenSSL::SSL::SSLContext#ciphers=}[rdoc-ref:OpenSSL::SSL::SSLContext#ciphers-3D].
- attr_accessor :ciphers
-
- # Sets or returns the extra X509 certificates to be added to the certificate chain.
- # See {OpenSSL::SSL::SSLContext#add_certificate}[rdoc-ref:OpenSSL::SSL::SSLContext#add_certificate].
- attr_accessor :extra_chain_cert
-
- # Sets or returns the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
- attr_accessor :key
-
- # Sets or returns the SSL timeout seconds.
- attr_accessor :ssl_timeout
-
- # Sets or returns the SSL version.
- # See {OpenSSL::SSL::SSLContext#ssl_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#ssl_version-3D].
- attr_accessor :ssl_version
-
- # Sets or returns the minimum SSL version.
- # See {OpenSSL::SSL::SSLContext#min_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#min_version-3D].
- attr_accessor :min_version
-
- # Sets or returns the maximum SSL version.
- # See {OpenSSL::SSL::SSLContext#max_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#max_version-3D].
- attr_accessor :max_version
-
- # Sets or returns the callback for the server certification verification.
- attr_accessor :verify_callback
-
- # Sets or returns the maximum depth for the certificate chain verification.
- attr_accessor :verify_depth
-
- # Sets or returns the flags for server the certification verification
- # at the beginning of the SSL/TLS session.
- # OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER are acceptable.
- attr_accessor :verify_mode
-
- # Sets or returns whether to verify that the server certificate is valid
- # for the hostname.
- # See {OpenSSL::SSL::SSLContext#verify_hostname=}[rdoc-ref:OpenSSL::SSL::SSLContext#attribute-i-verify_mode].
- attr_accessor :verify_hostname
-
- # Returns the X509 certificate chain (an array of strings)
- # for the session's socket peer,
- # or +nil+ if none.
- def peer_cert
- if not use_ssl? or not @socket
- return nil
- end
- @socket.io.peer_cert
- end
-
- # Starts an \HTTP session.
- #
- # Without a block, returns +self+:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.start
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=true>
- # http.started? # => true
- # http.finish
- #
- # With a block, calls the block with +self+,
- # finishes the session when the block exits,
- # and returns the block's value:
- #
- # http.start do |http|
- # http
- # end
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.started? # => false
- #
- def start # :yield: http
- raise IOError, 'HTTP session already opened' if @started
- if block_given?
- begin
- do_start
- return yield(self)
- ensure
- do_finish
- end
- end
- do_start
- self
- end
-
- def do_start
- connect
- @started = true
- end
- private :do_start
-
- def connect
- if use_ssl?
- # reference early to load OpenSSL before connecting,
- # as OpenSSL may take time to load.
- @ssl_context = OpenSSL::SSL::SSLContext.new
- end
-
- if proxy? then
- conn_addr = proxy_address
- conn_port = proxy_port
- else
- conn_addr = conn_address
- conn_port = port
- end
-
- debug "opening connection to #{conn_addr}:#{conn_port}..."
- s = Gem::Timeout.timeout(@open_timeout, Gem::Net::OpenTimeout) {
- begin
- TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
- rescue => e
- raise e, "Failed to open TCP connection to " +
- "#{conn_addr}:#{conn_port} (#{e.message})"
- end
- }
- s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
- debug "opened"
- if use_ssl?
- if proxy?
- plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
- write_timeout: @write_timeout,
- continue_timeout: @continue_timeout,
- debug_output: @debug_output)
- buf = +"CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n" \
- "Host: #{@address}:#{@port}\r\n"
- if proxy_user
- credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0')
- buf << "Proxy-Authorization: Basic #{credential}\r\n"
- end
- buf << "\r\n"
- plain_sock.write(buf)
- HTTPResponse.read_new(plain_sock).value
- # assuming nothing left in buffers after successful CONNECT response
- end
-
- ssl_parameters = Hash.new
- iv_list = instance_variables
- SSL_IVNAMES.each_with_index do |ivname, i|
- if iv_list.include?(ivname)
- value = instance_variable_get(ivname)
- unless value.nil?
- ssl_parameters[SSL_ATTRIBUTES[i]] = value
- end
- end
- end
- @ssl_context.set_params(ssl_parameters)
- unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
- @ssl_context.session_cache_mode =
- OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
- OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
- end
- if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
- @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
- end
-
- # Still do the post_connection_check below even if connecting
- # to IP address
- verify_hostname = @ssl_context.verify_hostname
-
- # Server Name Indication (SNI) RFC 3546/6066
- case @address
- when Gem::Resolv::IPv4::Regex, Gem::Resolv::IPv6::Regex
- # don't set SNI, as IP addresses in SNI is not valid
- # per RFC 6066, section 3.
-
- # Avoid openssl warning
- @ssl_context.verify_hostname = false
- else
- ssl_host_address = @address
- end
-
- debug "starting SSL for #{conn_addr}:#{conn_port}..."
- s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
- s.sync_close = true
- s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address
-
- if @ssl_session and
- Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
- s.session = @ssl_session
- end
- ssl_socket_connect(s, @open_timeout)
- if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
- s.post_connection_check(@address)
- end
- debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
- end
- @socket = BufferedIO.new(s, read_timeout: @read_timeout,
- write_timeout: @write_timeout,
- continue_timeout: @continue_timeout,
- debug_output: @debug_output)
- @last_communicated = nil
- on_connect
- rescue => exception
- if s
- debug "Conn close because of connect error #{exception}"
- s.close
- end
- raise
- end
- private :connect
-
- def on_connect
- end
- private :on_connect
-
- # Finishes the \HTTP session:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.start
- # http.started? # => true
- # http.finish # => nil
- # http.started? # => false
- #
- # Raises IOError if not in a session.
- def finish
- raise IOError, 'HTTP session not yet started' unless started?
- do_finish
- end
-
- def do_finish
- @started = false
- @socket.close if @socket
- @socket = nil
- end
- private :do_finish
-
- #
- # proxy
- #
-
- public
-
- # no proxy
- @is_proxy_class = false
- @proxy_from_env = false
- @proxy_addr = nil
- @proxy_port = nil
- @proxy_user = nil
- @proxy_pass = nil
-
- # Creates an \HTTP proxy class which behaves like \Gem::Net::HTTP, but
- # performs all access via the specified proxy.
- #
- # This class is obsolete. You may pass these same parameters directly to
- # \Gem::Net::HTTP.new. See Gem::Net::HTTP.new for details of the arguments.
- def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil) #:nodoc:
- return self unless p_addr
-
- Class.new(self) {
- @is_proxy_class = true
-
- if p_addr == :ENV then
- @proxy_from_env = true
- @proxy_address = nil
- @proxy_port = nil
- else
- @proxy_from_env = false
- @proxy_address = p_addr
- @proxy_port = p_port || default_port
- end
-
- @proxy_user = p_user
- @proxy_pass = p_pass
- }
- end
-
- class << HTTP
- # Returns true if self is a class which was created by HTTP::Proxy.
- def proxy_class?
- defined?(@is_proxy_class) ? @is_proxy_class : false
- end
-
- # Returns the address of the proxy host, or +nil+ if none;
- # see Gem::Net::HTTP@Proxy+Server.
- attr_reader :proxy_address
-
- # Returns the port number of the proxy host, or +nil+ if none;
- # see Gem::Net::HTTP@Proxy+Server.
- attr_reader :proxy_port
-
- # Returns the user name for accessing the proxy, or +nil+ if none;
- # see Gem::Net::HTTP@Proxy+Server.
- attr_reader :proxy_user
-
- # Returns the password for accessing the proxy, or +nil+ if none;
- # see Gem::Net::HTTP@Proxy+Server.
- attr_reader :proxy_pass
- end
-
- # Returns +true+ if a proxy server is defined, +false+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy?
- !!(@proxy_from_env ? proxy_uri : @proxy_address)
- end
-
- # Returns +true+ if the proxy server is defined in the environment,
- # +false+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_from_env?
- @proxy_from_env
- end
-
- # The proxy URI determined from the environment for this connection.
- def proxy_uri # :nodoc:
- return if @proxy_uri == false
- @proxy_uri ||= Gem::URI::HTTP.new(
- "http", nil, address, port, nil, nil, nil, nil, nil
- ).find_proxy || false
- @proxy_uri || nil
- end
-
- # Returns the address of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_address
- if @proxy_from_env then
- proxy_uri&.hostname
- else
- @proxy_address
- end
- end
-
- # Returns the port number of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_port
- if @proxy_from_env then
- proxy_uri&.port
- else
- @proxy_port
- end
- end
-
- # Returns the user name of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_user
- if @proxy_from_env
- user = proxy_uri&.user
- unescape(user) if user
- else
- @proxy_user
- end
- end
-
- # Returns the password of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_pass
- if @proxy_from_env
- pass = proxy_uri&.password
- unescape(pass) if pass
- else
- @proxy_pass
- end
- end
-
- alias proxyaddr proxy_address #:nodoc: obsolete
- alias proxyport proxy_port #:nodoc: obsolete
-
- private
-
- def unescape(value)
- require 'cgi/util'
- CGI.unescape(value)
- end
-
- # without proxy, obsolete
-
- def conn_address # :nodoc:
- @ipaddr || address()
- end
-
- def conn_port # :nodoc:
- port()
- end
-
- def edit_path(path)
- if proxy?
- if path.start_with?("ftp://") || use_ssl?
- path
- else
- "http://#{addr_port}#{path}"
- end
- else
- path
- end
- end
-
- #
- # HTTP operations
- #
-
- public
-
- # :call-seq:
- # get(path, initheader = nil) {|res| ... }
- #
- # Sends a GET request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Get object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # With a block given, calls the block with the response body:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.get('/todos/1') do |res|
- # p res
- # end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n}"
- #
- # With no block given, simply returns the response object:
- #
- # http.get('/') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Related:
- #
- # - Gem::Net::HTTP::Get: request class for \HTTP method GET.
- # - Gem::Net::HTTP.get: sends GET request, returns response body.
- #
- def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
- res = nil
-
- request(Get.new(path, initheader)) {|r|
- r.read_body dest, &block
- res = r
- }
- res
- end
-
- # Sends a HEAD request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Head object
- # created from string +path+ and initial headers hash +initheader+:
- #
- # res = http.head('/todos/1') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- # res.body # => nil
- # res.to_hash.take(3)
- # # =>
- # [["date", ["Wed, 15 Feb 2023 15:25:42 GMT"]],
- # ["content-type", ["application/json; charset=utf-8"]],
- # ["connection", ["close"]]]
- #
- def head(path, initheader = nil)
- request(Head.new(path, initheader))
- end
-
- # :call-seq:
- # post(path, data, initheader = nil) {|res| ... }
- #
- # Sends a POST request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Post object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # With a block given, calls the block with the response body:
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.post('/todos', data) do |res|
- # p res
- # end # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # Output:
- #
- # "{\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\",\n \"id\": 201\n}"
- #
- # With no block given, simply returns the response object:
- #
- # http.post('/todos', data) # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # Related:
- #
- # - Gem::Net::HTTP::Post: request class for \HTTP method POST.
- # - Gem::Net::HTTP.post: sends POST request, returns response body.
- #
- def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
- send_entity(path, data, initheader, dest, Post, &block)
- end
-
- # :call-seq:
- # patch(path, data, initheader = nil) {|res| ... }
- #
- # Sends a PATCH request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Patch object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # With a block given, calls the block with the response body:
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.patch('/todos/1', data) do |res|
- # p res
- # end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false,\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\"\n}"
- #
- # With no block given, simply returns the response object:
- #
- # http.patch('/todos/1', data) # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
- send_entity(path, data, initheader, dest, Patch, &block)
- end
-
- # Sends a PUT request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Put object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.put('/todos/1', data) # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- def put(path, data, initheader = nil)
- request(Put.new(path, initheader), data)
- end
-
- # Sends a PROPPATCH request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Proppatch object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.proppatch('/todos/1', data)
- #
- def proppatch(path, body, initheader = nil)
- request(Proppatch.new(path, initheader), body)
- end
-
- # Sends a LOCK request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Lock object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.lock('/todos/1', data)
- #
- def lock(path, body, initheader = nil)
- request(Lock.new(path, initheader), body)
- end
-
- # Sends an UNLOCK request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Unlock object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.unlock('/todos/1', data)
- #
- def unlock(path, body, initheader = nil)
- request(Unlock.new(path, initheader), body)
- end
-
- # Sends an Options request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Options object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.options('/')
- #
- def options(path, initheader = nil)
- request(Options.new(path, initheader))
- end
-
- # Sends a PROPFIND request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Propfind object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.propfind('/todos/1', data)
- #
- def propfind(path, body = nil, initheader = {'Depth' => '0'})
- request(Propfind.new(path, initheader), body)
- end
-
- # Sends a DELETE request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Delete object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.delete('/todos/1')
- #
- def delete(path, initheader = {'Depth' => 'Infinity'})
- request(Delete.new(path, initheader))
- end
-
- # Sends a MOVE request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Move object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.move('/todos/1')
- #
- def move(path, initheader = nil)
- request(Move.new(path, initheader))
- end
-
- # Sends a COPY request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Copy object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.copy('/todos/1')
- #
- def copy(path, initheader = nil)
- request(Copy.new(path, initheader))
- end
-
- # Sends a MKCOL request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Mkcol object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http.mkcol('/todos/1', data)
- # http = Gem::Net::HTTP.new(hostname)
- #
- def mkcol(path, body = nil, initheader = nil)
- request(Mkcol.new(path, initheader), body)
- end
-
- # Sends a TRACE request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Trace object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.trace('/todos/1')
- #
- def trace(path, initheader = nil)
- request(Trace.new(path, initheader))
- end
-
- # Sends a GET request to the server;
- # forms the response into a Gem::Net::HTTPResponse object.
- #
- # The request is based on the Gem::Net::HTTP::Get object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # With no block given, returns the response object:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.request_get('/todos') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # With a block given, calls the block with the response object
- # and returns the response object:
- #
- # http.request_get('/todos') do |res|
- # p res
- # end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # #<Gem::Net::HTTPOK 200 OK readbody=false>
- #
- def request_get(path, initheader = nil, &block) # :yield: +response+
- request(Get.new(path, initheader), &block)
- end
-
- # Sends a HEAD request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Head object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.head('/todos/1') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- def request_head(path, initheader = nil, &block)
- request(Head.new(path, initheader), &block)
- end
-
- # Sends a POST request to the server;
- # forms the response into a Gem::Net::HTTPResponse object.
- #
- # The request is based on the Gem::Net::HTTP::Post object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # With no block given, returns the response object:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.post('/todos', 'xyzzy')
- # # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # With a block given, calls the block with the response body
- # and returns the response object:
- #
- # http.post('/todos', 'xyzzy') do |res|
- # p res
- # end # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # Output:
- #
- # "{\n \"xyzzy\": \"\",\n \"id\": 201\n}"
- #
- def request_post(path, data, initheader = nil, &block) # :yield: +response+
- request Post.new(path, initheader), data, &block
- end
-
- # Sends a PUT request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Put object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.put('/todos/1', 'xyzzy')
- # # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- def request_put(path, data, initheader = nil, &block) #:nodoc:
- request Put.new(path, initheader), data, &block
- end
-
- alias get2 request_get #:nodoc: obsolete
- alias head2 request_head #:nodoc: obsolete
- alias post2 request_post #:nodoc: obsolete
- alias put2 request_put #:nodoc: obsolete
-
- # Sends an \HTTP request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTPRequest object
- # created from string +path+, string +data+, and initial headers hash +header+.
- # That object is an instance of the
- # {subclass of Gem::Net::HTTPRequest}[rdoc-ref:Gem::Net::HTTPRequest@Request+Subclasses],
- # that corresponds to the given uppercase string +name+,
- # which must be
- # an {HTTP request method}[https://en.wikipedia.org/wiki/HTTP#Request_methods]
- # or a {WebDAV request method}[https://en.wikipedia.org/wiki/WebDAV#Implementation].
- #
- # Examples:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.send_request('GET', '/todos/1')
- # # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- # http.send_request('POST', '/todos', 'xyzzy')
- # # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- def send_request(name, path, data = nil, header = nil)
- has_response_body = name != 'HEAD'
- r = HTTPGenericRequest.new(name,(data ? true : false),has_response_body,path,header)
- request r, data
- end
-
- # Sends the given request +req+ to the server;
- # forms the response into a Gem::Net::HTTPResponse object.
- #
- # The given +req+ must be an instance of a
- # {subclass of Gem::Net::HTTPRequest}[rdoc-ref:Gem::Net::HTTPRequest@Request+Subclasses].
- # Argument +body+ should be given only if needed for the request.
- #
- # With no block given, returns the response object:
- #
- # http = Gem::Net::HTTP.new(hostname)
- #
- # req = Gem::Net::HTTP::Get.new('/todos/1')
- # http.request(req)
- # # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # req = Gem::Net::HTTP::Post.new('/todos')
- # http.request(req, 'xyzzy')
- # # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # With a block given, calls the block with the response and returns the response:
- #
- # req = Gem::Net::HTTP::Get.new('/todos/1')
- # http.request(req) do |res|
- # p res
- # end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # #<Gem::Net::HTTPOK 200 OK readbody=false>
- #
- def request(req, body = nil, &block) # :yield: +response+
- unless started?
- start {
- req['connection'] ||= 'close'
- return request(req, body, &block)
- }
- end
- if proxy_user()
- req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl?
- end
- req.set_body_internal body
- res = transport_request(req, &block)
- if sspi_auth?(res)
- sspi_auth(req)
- res = transport_request(req, &block)
- end
- res
- end
-
- private
-
- # Executes a request which uses a representation
- # and returns its body.
- def send_entity(path, data, initheader, dest, type, &block)
- res = nil
- request(type.new(path, initheader), data) {|r|
- r.read_body dest, &block
- res = r
- }
- res
- end
-
- IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
-
- def transport_request(req)
- count = 0
- begin
- begin_transport req
- res = catch(:response) {
- begin
- req.exec @socket, @curr_http_version, edit_path(req.path)
- rescue Errno::EPIPE
- # Failure when writing full request, but we can probably
- # still read the received response.
- end
-
- begin
- res = HTTPResponse.read_new(@socket)
- res.decode_content = req.decode_content
- res.body_encoding = @response_body_encoding
- res.ignore_eof = @ignore_eof
- end while res.kind_of?(HTTPInformation)
-
- res.uri = req.uri
-
- res
- }
- res.reading_body(@socket, req.response_body_permitted?) {
- yield res if block_given?
- }
- rescue Gem::Net::OpenTimeout
- raise
- rescue Gem::Net::ReadTimeout, IOError, EOFError,
- Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, Errno::ETIMEDOUT,
- # avoid a dependency on OpenSSL
- defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError,
- Gem::Timeout::Error => exception
- if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method)
- count += 1
- @socket.close if @socket
- debug "Conn close because of error #{exception}, and retry"
- retry
- end
- debug "Conn close because of error #{exception}"
- @socket.close if @socket
- raise
- end
-
- end_transport req, res
- res
- rescue => exception
- debug "Conn close because of error #{exception}"
- @socket.close if @socket
- raise exception
- end
-
- def begin_transport(req)
- if @socket.closed?
- connect
- elsif @last_communicated
- if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC)
- debug 'Conn close because of keep_alive_timeout'
- @socket.close
- connect
- elsif @socket.io.to_io.wait_readable(0) && @socket.eof?
- debug "Conn close because of EOF"
- @socket.close
- connect
- end
- end
-
- if not req.response_body_permitted? and @close_on_empty_response
- req['connection'] ||= 'close'
- end
-
- req.update_uri address, port, use_ssl?
- req['host'] ||= addr_port()
- end
-
- def end_transport(req, res)
- @curr_http_version = res.http_version
- @last_communicated = nil
- if @socket.closed?
- debug 'Conn socket closed'
- elsif not res.body and @close_on_empty_response
- debug 'Conn close'
- @socket.close
- elsif keep_alive?(req, res)
- debug 'Conn keep-alive'
- @last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- else
- debug 'Conn close'
- @socket.close
- end
- end
-
- def keep_alive?(req, res)
- return false if req.connection_close?
- if @curr_http_version <= '1.0'
- res.connection_keep_alive?
- else # HTTP/1.1 or later
- not res.connection_close?
- end
- end
-
- def sspi_auth?(res)
- return false unless @sspi_enabled
- if res.kind_of?(HTTPProxyAuthenticationRequired) and
- proxy? and res["Proxy-Authenticate"].include?("Negotiate")
- begin
- require 'win32/sspi'
- true
- rescue LoadError
- false
- end
- else
- false
- end
- end
-
- def sspi_auth(req)
- n = Win32::SSPI::NegotiateAuth.new
- req["Proxy-Authorization"] = "Negotiate #{n.get_initial_token}"
- # Some versions of ISA will close the connection if this isn't present.
- req["Connection"] = "Keep-Alive"
- req["Proxy-Connection"] = "Keep-Alive"
- res = transport_request(req)
- authphrase = res["Proxy-Authenticate"] or return res
- req["Proxy-Authorization"] = "Negotiate #{n.complete_authentication(authphrase)}"
- rescue => err
- raise HTTPAuthenticationError.new('HTTP authentication failed', err)
- end
-
- #
- # utils
- #
-
- private
-
- def addr_port
- addr = address
- addr = "[#{addr}]" if addr.include?(":")
- default_port = use_ssl? ? HTTP.https_default_port : HTTP.http_default_port
- default_port == port ? addr : "#{addr}:#{port}"
- end
-
- # Adds a message to debugging output
- def debug(msg)
- return unless @debug_output
- @debug_output << msg
- @debug_output << "\n"
- end
-
- alias_method :D, :debug
- end
-
-end
-
-require_relative 'http/exceptions'
-
-require_relative 'http/header'
-
-require_relative 'http/generic_request'
-require_relative 'http/request'
-require_relative 'http/requests'
-
-require_relative 'http/response'
-require_relative 'http/responses'
-
-require_relative 'http/proxy_delta'
-
-require_relative 'http/backward'
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/backward.rb b/lib/rubygems/vendor/net-http/lib/net/http/backward.rb
deleted file mode 100644
index 10dbc16224..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/backward.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-# for backward compatibility
-
-# :enddoc:
-
-class Gem::Net::HTTP
- ProxyMod = ProxyDelta
- deprecate_constant :ProxyMod
-end
-
-module Gem::Net::NetPrivate
- HTTPRequest = ::Gem::Net::HTTPRequest
- deprecate_constant :HTTPRequest
-end
-
-module Gem::Net
- HTTPSession = HTTP
-
- HTTPInformationCode = HTTPInformation
- HTTPSuccessCode = HTTPSuccess
- HTTPRedirectionCode = HTTPRedirection
- HTTPRetriableCode = HTTPRedirection
- HTTPClientErrorCode = HTTPClientError
- HTTPFatalErrorCode = HTTPClientError
- HTTPServerErrorCode = HTTPServerError
- HTTPResponseReceiver = HTTPResponse
-
- HTTPResponceReceiver = HTTPResponse # Typo since 2001
-
- deprecate_constant :HTTPSession,
- :HTTPInformationCode,
- :HTTPSuccessCode,
- :HTTPRedirectionCode,
- :HTTPRetriableCode,
- :HTTPClientErrorCode,
- :HTTPFatalErrorCode,
- :HTTPServerErrorCode,
- :HTTPResponseReceiver,
- :HTTPResponceReceiver
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb b/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
deleted file mode 100644
index c629c0113b..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-module Gem::Net
- # Gem::Net::HTTP exception class.
- # You cannot use Gem::Net::HTTPExceptions directly; instead, you must use
- # its subclasses.
- module HTTPExceptions
- def initialize(msg, res) #:nodoc:
- super msg
- @response = res
- end
- attr_reader :response
- alias data response #:nodoc: obsolete
- end
-
- class HTTPError < ProtocolError
- include HTTPExceptions
- end
-
- class HTTPRetriableError < ProtoRetriableError
- include HTTPExceptions
- end
-
- class HTTPClientException < ProtoServerError
- include HTTPExceptions
- end
-
- class HTTPFatalError < ProtoFatalError
- include HTTPExceptions
- end
-
- # We cannot use the name "HTTPServerError", it is the name of the response.
- HTTPServerException = HTTPClientException # :nodoc:
- deprecate_constant(:HTTPServerException)
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb b/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb
deleted file mode 100644
index 5cfe75a7cd..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb
+++ /dev/null
@@ -1,414 +0,0 @@
-# frozen_string_literal: true
-#
-# \HTTPGenericRequest is the parent of the Gem::Net::HTTPRequest class.
-#
-# Do not use this directly; instead, use a subclass of Gem::Net::HTTPRequest.
-#
-# == About the Examples
-#
-# :include: doc/net-http/examples.rdoc
-#
-class Gem::Net::HTTPGenericRequest
-
- include Gem::Net::HTTPHeader
-
- def initialize(m, reqbody, resbody, uri_or_path, initheader = nil) # :nodoc:
- @method = m
- @request_has_body = reqbody
- @response_has_body = resbody
-
- if Gem::URI === uri_or_path then
- raise ArgumentError, "not an HTTP Gem::URI" unless Gem::URI::HTTP === uri_or_path
- hostname = uri_or_path.hostname
- raise ArgumentError, "no host component for Gem::URI" unless (hostname && hostname.length > 0)
- @uri = uri_or_path.dup
- host = @uri.hostname.dup
- host << ":" << @uri.port.to_s if @uri.port != @uri.default_port
- @path = uri_or_path.request_uri
- raise ArgumentError, "no HTTP request path given" unless @path
- else
- @uri = nil
- host = nil
- raise ArgumentError, "no HTTP request path given" unless uri_or_path
- raise ArgumentError, "HTTP request path is empty" if uri_or_path.empty?
- @path = uri_or_path.dup
- end
-
- @decode_content = false
-
- if Gem::Net::HTTP::HAVE_ZLIB then
- if !initheader ||
- !initheader.keys.any? { |k|
- %w[accept-encoding range].include? k.downcase
- } then
- @decode_content = true if @response_has_body
- initheader = initheader ? initheader.dup : {}
- initheader["accept-encoding"] =
- "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
- end
- end
-
- initialize_http_header initheader
- self['Accept'] ||= '*/*'
- self['User-Agent'] ||= 'Ruby'
- self['Host'] ||= host if host
- @body = nil
- @body_stream = nil
- @body_data = nil
- end
-
- # Returns the string method name for the request:
- #
- # Gem::Net::HTTP::Get.new(uri).method # => "GET"
- # Gem::Net::HTTP::Post.new(uri).method # => "POST"
- #
- attr_reader :method
-
- # Returns the string path for the request:
- #
- # Gem::Net::HTTP::Get.new(uri).path # => "/"
- # Gem::Net::HTTP::Post.new('example.com').path # => "example.com"
- #
- attr_reader :path
-
- # Returns the Gem::URI object for the request, or +nil+ if none:
- #
- # Gem::Net::HTTP::Get.new(uri).uri
- # # => #<Gem::URI::HTTPS https://jsonplaceholder.typicode.com/>
- # Gem::Net::HTTP::Get.new('example.com').uri # => nil
- #
- attr_reader :uri
-
- # Returns +false+ if the request's header <tt>'Accept-Encoding'</tt>
- # has been set manually or deleted
- # (indicating that the user intends to handle encoding in the response),
- # +true+ otherwise:
- #
- # req = Gem::Net::HTTP::Get.new(uri) # => #<Gem::Net::HTTP::Get GET>
- # req['Accept-Encoding'] # => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
- # req.decode_content # => true
- # req['Accept-Encoding'] = 'foo'
- # req.decode_content # => false
- # req.delete('Accept-Encoding')
- # req.decode_content # => false
- #
- attr_reader :decode_content
-
- # Returns a string representation of the request:
- #
- # Gem::Net::HTTP::Post.new(uri).inspect # => "#<Gem::Net::HTTP::Post POST>"
- #
- def inspect
- "\#<#{self.class} #{@method}>"
- end
-
- ##
- # Don't automatically decode response content-encoding if the user indicates
- # they want to handle it.
-
- def []=(key, val) # :nodoc:
- @decode_content = false if key.downcase == 'accept-encoding'
-
- super key, val
- end
-
- # Returns whether the request may have a body:
- #
- # Gem::Net::HTTP::Post.new(uri).request_body_permitted? # => true
- # Gem::Net::HTTP::Get.new(uri).request_body_permitted? # => false
- #
- def request_body_permitted?
- @request_has_body
- end
-
- # Returns whether the response may have a body:
- #
- # Gem::Net::HTTP::Post.new(uri).response_body_permitted? # => true
- # Gem::Net::HTTP::Head.new(uri).response_body_permitted? # => false
- #
- def response_body_permitted?
- @response_has_body
- end
-
- def body_exist? # :nodoc:
- warn "Gem::Net::HTTPRequest#body_exist? is obsolete; use response_body_permitted?", uplevel: 1 if $VERBOSE
- response_body_permitted?
- end
-
- # Returns the string body for the request, or +nil+ if there is none:
- #
- # req = Gem::Net::HTTP::Post.new(uri)
- # req.body # => nil
- # req.body = '{"title": "foo","body": "bar","userId": 1}'
- # req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"
- #
- attr_reader :body
-
- # Sets the body for the request:
- #
- # req = Gem::Net::HTTP::Post.new(uri)
- # req.body # => nil
- # req.body = '{"title": "foo","body": "bar","userId": 1}'
- # req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"
- #
- def body=(str)
- @body = str
- @body_stream = nil
- @body_data = nil
- str
- end
-
- # Returns the body stream object for the request, or +nil+ if there is none:
- #
- # req = Gem::Net::HTTP::Post.new(uri) # => #<Gem::Net::HTTP::Post POST>
- # req.body_stream # => nil
- # require 'stringio'
- # req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8>
- # req.body_stream # => #<StringIO:0x0000027d1e5affa8>
- #
- attr_reader :body_stream
-
- # Sets the body stream for the request:
- #
- # req = Gem::Net::HTTP::Post.new(uri) # => #<Gem::Net::HTTP::Post POST>
- # req.body_stream # => nil
- # require 'stringio'
- # req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8>
- # req.body_stream # => #<StringIO:0x0000027d1e5affa8>
- #
- def body_stream=(input)
- @body = nil
- @body_stream = input
- @body_data = nil
- input
- end
-
- def set_body_internal(str) #:nodoc: internal use only
- raise ArgumentError, "both of body argument and HTTPRequest#body set" if str and (@body or @body_stream)
- self.body = str if str
- if @body.nil? && @body_stream.nil? && @body_data.nil? && request_body_permitted?
- self.body = ''
- end
- end
-
- #
- # write
- #
-
- def exec(sock, ver, path) #:nodoc: internal use only
- if @body
- send_request_with_body sock, ver, path, @body
- elsif @body_stream
- send_request_with_body_stream sock, ver, path, @body_stream
- elsif @body_data
- send_request_with_body_data sock, ver, path, @body_data
- else
- write_header sock, ver, path
- end
- end
-
- def update_uri(addr, port, ssl) # :nodoc: internal use only
- # reflect the connection and @path to @uri
- return unless @uri
-
- if ssl
- scheme = 'https'
- klass = Gem::URI::HTTPS
- else
- scheme = 'http'
- klass = Gem::URI::HTTP
- end
-
- if host = self['host']
- host.sub!(/:.*/m, '')
- elsif host = @uri.host
- else
- host = addr
- end
- # convert the class of the Gem::URI
- if @uri.is_a?(klass)
- @uri.host = host
- @uri.port = port
- else
- @uri = klass.new(
- scheme, @uri.userinfo,
- host, port, nil,
- @uri.path, nil, @uri.query, nil)
- end
- end
-
- private
-
- class Chunker #:nodoc:
- def initialize(sock)
- @sock = sock
- @prev = nil
- end
-
- def write(buf)
- # avoid memcpy() of buf, buf can huge and eat memory bandwidth
- rv = buf.bytesize
- @sock.write("#{rv.to_s(16)}\r\n", buf, "\r\n")
- rv
- end
-
- def finish
- @sock.write("0\r\n\r\n")
- end
- end
-
- def send_request_with_body(sock, ver, path, body)
- self.content_length = body.bytesize
- delete 'Transfer-Encoding'
- supply_default_content_type
- write_header sock, ver, path
- wait_for_continue sock, ver if sock.continue_timeout
- sock.write body
- end
-
- def send_request_with_body_stream(sock, ver, path, f)
- unless content_length() or chunked?
- raise ArgumentError,
- "Content-Length not given and Transfer-Encoding is not `chunked'"
- end
- supply_default_content_type
- write_header sock, ver, path
- wait_for_continue sock, ver if sock.continue_timeout
- if chunked?
- chunker = Chunker.new(sock)
- IO.copy_stream(f, chunker)
- chunker.finish
- else
- IO.copy_stream(f, sock)
- end
- end
-
- def send_request_with_body_data(sock, ver, path, params)
- if /\Amultipart\/form-data\z/i !~ self.content_type
- self.content_type = 'application/x-www-form-urlencoded'
- return send_request_with_body(sock, ver, path, Gem::URI.encode_www_form(params))
- end
-
- opt = @form_option.dup
- require 'securerandom' unless defined?(SecureRandom)
- opt[:boundary] ||= SecureRandom.urlsafe_base64(40)
- self.set_content_type(self.content_type, boundary: opt[:boundary])
- if chunked?
- write_header sock, ver, path
- encode_multipart_form_data(sock, params, opt)
- else
- require 'tempfile'
- file = Tempfile.new('multipart')
- file.binmode
- encode_multipart_form_data(file, params, opt)
- file.rewind
- self.content_length = file.size
- write_header sock, ver, path
- IO.copy_stream(file, sock)
- file.close(true)
- end
- end
-
- def encode_multipart_form_data(out, params, opt)
- charset = opt[:charset]
- boundary = opt[:boundary]
- require 'securerandom' unless defined?(SecureRandom)
- boundary ||= SecureRandom.urlsafe_base64(40)
- chunked_p = chunked?
-
- buf = +''
- params.each do |key, value, h={}|
- key = quote_string(key, charset)
- filename =
- h.key?(:filename) ? h[:filename] :
- value.respond_to?(:to_path) ? File.basename(value.to_path) :
- nil
-
- buf << "--#{boundary}\r\n"
- if filename
- filename = quote_string(filename, charset)
- type = h[:content_type] || 'application/octet-stream'
- buf << "Content-Disposition: form-data; " \
- "name=\"#{key}\"; filename=\"#{filename}\"\r\n" \
- "Content-Type: #{type}\r\n\r\n"
- if !out.respond_to?(:write) || !value.respond_to?(:read)
- # if +out+ is not an IO or +value+ is not an IO
- buf << (value.respond_to?(:read) ? value.read : value)
- elsif value.respond_to?(:size) && chunked_p
- # if +out+ is an IO and +value+ is a File, use IO.copy_stream
- flush_buffer(out, buf, chunked_p)
- out << "%x\r\n" % value.size if chunked_p
- IO.copy_stream(value, out)
- out << "\r\n" if chunked_p
- else
- # +out+ is an IO, and +value+ is not a File but an IO
- flush_buffer(out, buf, chunked_p)
- 1 while flush_buffer(out, value.read(4096), chunked_p)
- end
- else
- # non-file field:
- # HTML5 says, "The parts of the generated multipart/form-data
- # resource that correspond to non-file fields must not have a
- # Content-Type header specified."
- buf << "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
- buf << (value.respond_to?(:read) ? value.read : value)
- end
- buf << "\r\n"
- end
- buf << "--#{boundary}--\r\n"
- flush_buffer(out, buf, chunked_p)
- out << "0\r\n\r\n" if chunked_p
- end
-
- def quote_string(str, charset)
- str = str.encode(charset, fallback:->(c){'&#%d;'%c.encode("UTF-8").ord}) if charset
- str.gsub(/[\\"]/, '\\\\\&')
- end
-
- def flush_buffer(out, buf, chunked_p)
- return unless buf
- out << "%x\r\n"%buf.bytesize if chunked_p
- out << buf
- out << "\r\n" if chunked_p
- buf.clear
- end
-
- def supply_default_content_type
- return if content_type()
- warn 'net/http: Content-Type did not set; using application/x-www-form-urlencoded', uplevel: 1 if $VERBOSE
- set_content_type 'application/x-www-form-urlencoded'
- end
-
- ##
- # Waits up to the continue timeout for a response from the server provided
- # we're speaking HTTP 1.1 and are expecting a 100-continue response.
-
- def wait_for_continue(sock, ver)
- if ver >= '1.1' and @header['expect'] and
- @header['expect'].include?('100-continue')
- if sock.io.to_io.wait_readable(sock.continue_timeout)
- res = Gem::Net::HTTPResponse.read_new(sock)
- unless res.kind_of?(Gem::Net::HTTPContinue)
- res.decode_content = @decode_content
- throw :response, res
- end
- end
- end
- end
-
- def write_header(sock, ver, path)
- reqline = "#{@method} #{path} HTTP/#{ver}"
- if /[\r\n]/ =~ reqline
- raise ArgumentError, "A Request-Line must not contain CR or LF"
- end
- buf = +''
- buf << reqline << "\r\n"
- each_capitalized do |k,v|
- buf << "#{k}: #{v}\r\n"
- end
- buf << "\r\n"
- sock.write buf
- end
-
-end
-
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/header.rb b/lib/rubygems/vendor/net-http/lib/net/http/header.rb
deleted file mode 100644
index 1488e60068..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/header.rb
+++ /dev/null
@@ -1,981 +0,0 @@
-# frozen_string_literal: true
-#
-# The \HTTPHeader module provides access to \HTTP headers.
-#
-# The module is included in:
-#
-# - Gem::Net::HTTPGenericRequest (and therefore Gem::Net::HTTPRequest).
-# - Gem::Net::HTTPResponse.
-#
-# The headers are a hash-like collection of key/value pairs called _fields_.
-#
-# == Request and Response Fields
-#
-# Headers may be included in:
-#
-# - A Gem::Net::HTTPRequest object:
-# the object's headers will be sent with the request.
-# Any fields may be defined in the request;
-# see {Setters}[rdoc-ref:Gem::Net::HTTPHeader@Setters].
-# - A Gem::Net::HTTPResponse object:
-# the objects headers are usually those returned from the host.
-# Fields may be retrieved from the object;
-# see {Getters}[rdoc-ref:Gem::Net::HTTPHeader@Getters]
-# and {Iterators}[rdoc-ref:Gem::Net::HTTPHeader@Iterators].
-#
-# Exactly which fields should be sent or expected depends on the host;
-# see:
-#
-# - {Request fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields].
-# - {Response fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields].
-#
-# == About the Examples
-#
-# :include: doc/net-http/examples.rdoc
-#
-# == Fields
-#
-# A header field is a key/value pair.
-#
-# === Field Keys
-#
-# A field key may be:
-#
-# - A string: Key <tt>'Accept'</tt> is treated as if it were
-# <tt>'Accept'.downcase</tt>; i.e., <tt>'accept'</tt>.
-# - A symbol: Key <tt>:Accept</tt> is treated as if it were
-# <tt>:Accept.to_s.downcase</tt>; i.e., <tt>'accept'</tt>.
-#
-# Examples:
-#
-# req = Gem::Net::HTTP::Get.new(uri)
-# req[:accept] # => "*/*"
-# req['Accept'] # => "*/*"
-# req['ACCEPT'] # => "*/*"
-#
-# req['accept'] = 'text/html'
-# req[:accept] = 'text/html'
-# req['ACCEPT'] = 'text/html'
-#
-# === Field Values
-#
-# A field value may be returned as an array of strings or as a string:
-#
-# - These methods return field values as arrays:
-#
-# - #get_fields: Returns the array value for the given key,
-# or +nil+ if it does not exist.
-# - #to_hash: Returns a hash of all header fields:
-# each key is a field name; its value is the array value for the field.
-#
-# - These methods return field values as string;
-# the string value for a field is equivalent to
-# <tt>self[key.downcase.to_s].join(', '))</tt>:
-#
-# - #[]: Returns the string value for the given key,
-# or +nil+ if it does not exist.
-# - #fetch: Like #[], but accepts a default value
-# to be returned if the key does not exist.
-#
-# The field value may be set:
-#
-# - #[]=: Sets the value for the given key;
-# the given value may be a string, a symbol, an array, or a hash.
-# - #add_field: Adds a given value to a value for the given key
-# (not overwriting the existing value).
-# - #delete: Deletes the field for the given key.
-#
-# Example field values:
-#
-# - \String:
-#
-# req['Accept'] = 'text/html' # => "text/html"
-# req['Accept'] # => "text/html"
-# req.get_fields('Accept') # => ["text/html"]
-#
-# - \Symbol:
-#
-# req['Accept'] = :text # => :text
-# req['Accept'] # => "text"
-# req.get_fields('Accept') # => ["text"]
-#
-# - Simple array:
-#
-# req[:foo] = %w[bar baz bat]
-# req[:foo] # => "bar, baz, bat"
-# req.get_fields(:foo) # => ["bar", "baz", "bat"]
-#
-# - Simple hash:
-#
-# req[:foo] = {bar: 0, baz: 1, bat: 2}
-# req[:foo] # => "bar, 0, baz, 1, bat, 2"
-# req.get_fields(:foo) # => ["bar", "0", "baz", "1", "bat", "2"]
-#
-# - Nested:
-#
-# req[:foo] = [%w[bar baz], {bat: 0, bam: 1}]
-# req[:foo] # => "bar, baz, bat, 0, bam, 1"
-# req.get_fields(:foo) # => ["bar", "baz", "bat", "0", "bam", "1"]
-#
-# req[:foo] = {bar: %w[baz bat], bam: {bah: 0, bad: 1}}
-# req[:foo] # => "bar, baz, bat, bam, bah, 0, bad, 1"
-# req.get_fields(:foo) # => ["bar", "baz", "bat", "bam", "bah", "0", "bad", "1"]
-#
-# == Convenience Methods
-#
-# Various convenience methods retrieve values, set values, query values,
-# set form values, or iterate over fields.
-#
-# === Setters
-#
-# \Method #[]= can set any field, but does little to validate the new value;
-# some of the other setter methods provide some validation:
-#
-# - #[]=: Sets the string or array value for the given key.
-# - #add_field: Creates or adds to the array value for the given key.
-# - #basic_auth: Sets the string authorization header for <tt>'Authorization'</tt>.
-# - #content_length=: Sets the integer length for field <tt>'Content-Length</tt>.
-# - #content_type=: Sets the string value for field <tt>'Content-Type'</tt>.
-# - #proxy_basic_auth: Sets the string authorization header for <tt>'Proxy-Authorization'</tt>.
-# - #set_range: Sets the value for field <tt>'Range'</tt>.
-#
-# === Form Setters
-#
-# - #set_form: Sets an HTML form data set.
-# - #set_form_data: Sets header fields and a body from HTML form data.
-#
-# === Getters
-#
-# \Method #[] can retrieve the value of any field that exists,
-# but always as a string;
-# some of the other getter methods return something different
-# from the simple string value:
-#
-# - #[]: Returns the string field value for the given key.
-# - #content_length: Returns the integer value of field <tt>'Content-Length'</tt>.
-# - #content_range: Returns the Range value of field <tt>'Content-Range'</tt>.
-# - #content_type: Returns the string value of field <tt>'Content-Type'</tt>.
-# - #fetch: Returns the string field value for the given key.
-# - #get_fields: Returns the array field value for the given +key+.
-# - #main_type: Returns first part of the string value of field <tt>'Content-Type'</tt>.
-# - #sub_type: Returns second part of the string value of field <tt>'Content-Type'</tt>.
-# - #range: Returns an array of Range objects of field <tt>'Range'</tt>, or +nil+.
-# - #range_length: Returns the integer length of the range given in field <tt>'Content-Range'</tt>.
-# - #type_params: Returns the string parameters for <tt>'Content-Type'</tt>.
-#
-# === Queries
-#
-# - #chunked?: Returns whether field <tt>'Transfer-Encoding'</tt> is set to <tt>'chunked'</tt>.
-# - #connection_close?: Returns whether field <tt>'Connection'</tt> is set to <tt>'close'</tt>.
-# - #connection_keep_alive?: Returns whether field <tt>'Connection'</tt> is set to <tt>'keep-alive'</tt>.
-# - #key?: Returns whether a given key exists.
-#
-# === Iterators
-#
-# - #each_capitalized: Passes each field capitalized-name/value pair to the block.
-# - #each_capitalized_name: Passes each capitalized field name to the block.
-# - #each_header: Passes each field name/value pair to the block.
-# - #each_name: Passes each field name to the block.
-# - #each_value: Passes each string field value to the block.
-#
-module Gem::Net::HTTPHeader
- MAX_KEY_LENGTH = 1024
- MAX_FIELD_LENGTH = 65536
-
- def initialize_http_header(initheader) #:nodoc:
- @header = {}
- return unless initheader
- initheader.each do |key, value|
- warn "net/http: duplicated HTTP header: #{key}", uplevel: 3 if key?(key) and $VERBOSE
- if value.nil?
- warn "net/http: nil HTTP header: #{key}", uplevel: 3 if $VERBOSE
- else
- value = value.strip # raise error for invalid byte sequences
- if key.to_s.bytesize > MAX_KEY_LENGTH
- raise ArgumentError, "too long (#{key.bytesize} bytes) header: #{key[0, 30].inspect}..."
- end
- if value.to_s.bytesize > MAX_FIELD_LENGTH
- raise ArgumentError, "header #{key} has too long field value: #{value.bytesize}"
- end
- if value.count("\r\n") > 0
- raise ArgumentError, "header #{key} has field value #{value.inspect}, this cannot include CR/LF"
- end
- @header[key.downcase.to_s] = [value]
- end
- end
- end
-
- def size #:nodoc: obsolete
- @header.size
- end
-
- alias length size #:nodoc: obsolete
-
- # Returns the string field value for the case-insensitive field +key+,
- # or +nil+ if there is no such key;
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['Connection'] # => "keep-alive"
- # res['Nosuch'] # => nil
- #
- # Note that some field values may be retrieved via convenience methods;
- # see {Getters}[rdoc-ref:Gem::Net::HTTPHeader@Getters].
- def [](key)
- a = @header[key.downcase.to_s] or return nil
- a.join(', ')
- end
-
- # Sets the value for the case-insensitive +key+ to +val+,
- # overwriting the previous value if the field exists;
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req['Accept'] # => "*/*"
- # req['Accept'] = 'text/html'
- # req['Accept'] # => "text/html"
- #
- # Note that some field values may be set via convenience methods;
- # see {Setters}[rdoc-ref:Gem::Net::HTTPHeader@Setters].
- def []=(key, val)
- unless val
- @header.delete key.downcase.to_s
- return val
- end
- set_field(key, val)
- end
-
- # Adds value +val+ to the value array for field +key+ if the field exists;
- # creates the field with the given +key+ and +val+ if it does not exist.
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.add_field('Foo', 'bar')
- # req['Foo'] # => "bar"
- # req.add_field('Foo', 'baz')
- # req['Foo'] # => "bar, baz"
- # req.add_field('Foo', %w[baz bam])
- # req['Foo'] # => "bar, baz, baz, bam"
- # req.get_fields('Foo') # => ["bar", "baz", "baz", "bam"]
- #
- def add_field(key, val)
- stringified_downcased_key = key.downcase.to_s
- if @header.key?(stringified_downcased_key)
- append_field_value(@header[stringified_downcased_key], val)
- else
- set_field(key, val)
- end
- end
-
- private def set_field(key, val)
- case val
- when Enumerable
- ary = []
- append_field_value(ary, val)
- @header[key.downcase.to_s] = ary
- else
- val = val.to_s # for compatibility use to_s instead of to_str
- if val.b.count("\r\n") > 0
- raise ArgumentError, 'header field value cannot include CR/LF'
- end
- @header[key.downcase.to_s] = [val]
- end
- end
-
- private def append_field_value(ary, val)
- case val
- when Enumerable
- val.each{|x| append_field_value(ary, x)}
- else
- val = val.to_s
- if /[\r\n]/n.match?(val.b)
- raise ArgumentError, 'header field value cannot include CR/LF'
- end
- ary.push val
- end
- end
-
- # Returns the array field value for the given +key+,
- # or +nil+ if there is no such field;
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.get_fields('Connection') # => ["keep-alive"]
- # res.get_fields('Nosuch') # => nil
- #
- def get_fields(key)
- stringified_downcased_key = key.downcase.to_s
- return nil unless @header[stringified_downcased_key]
- @header[stringified_downcased_key].dup
- end
-
- # call-seq:
- # fetch(key, default_val = nil) {|key| ... } -> object
- # fetch(key, default_val = nil) -> value or default_val
- #
- # With a block, returns the string value for +key+ if it exists;
- # otherwise returns the value of the block;
- # ignores the +default_val+;
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- #
- # # Field exists; block not called.
- # res.fetch('Connection') do |value|
- # fail 'Cannot happen'
- # end # => "keep-alive"
- #
- # # Field does not exist; block called.
- # res.fetch('Nosuch') do |value|
- # value.downcase
- # end # => "nosuch"
- #
- # With no block, returns the string value for +key+ if it exists;
- # otherwise, returns +default_val+ if it was given;
- # otherwise raises an exception:
- #
- # res.fetch('Connection', 'Foo') # => "keep-alive"
- # res.fetch('Nosuch', 'Foo') # => "Foo"
- # res.fetch('Nosuch') # Raises KeyError.
- #
- def fetch(key, *args, &block) #:yield: +key+
- a = @header.fetch(key.downcase.to_s, *args, &block)
- a.kind_of?(Array) ? a.join(', ') : a
- end
-
- # Calls the block with each key/value pair:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.each_header do |key, value|
- # p [key, value] if key.start_with?('c')
- # end
- #
- # Output:
- #
- # ["content-type", "application/json; charset=utf-8"]
- # ["connection", "keep-alive"]
- # ["cache-control", "max-age=43200"]
- # ["cf-cache-status", "HIT"]
- # ["cf-ray", "771d17e9bc542cf5-ORD"]
- #
- # Returns an enumerator if no block is given.
- #
- # Gem::Net::HTTPHeader#each is an alias for Gem::Net::HTTPHeader#each_header.
- def each_header #:yield: +key+, +value+
- block_given? or return enum_for(__method__) { @header.size }
- @header.each do |k,va|
- yield k, va.join(', ')
- end
- end
-
- alias each each_header
-
- # Calls the block with each field key:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.each_key do |key|
- # p key if key.start_with?('c')
- # end
- #
- # Output:
- #
- # "content-type"
- # "connection"
- # "cache-control"
- # "cf-cache-status"
- # "cf-ray"
- #
- # Returns an enumerator if no block is given.
- #
- # Gem::Net::HTTPHeader#each_name is an alias for Gem::Net::HTTPHeader#each_key.
- def each_name(&block) #:yield: +key+
- block_given? or return enum_for(__method__) { @header.size }
- @header.each_key(&block)
- end
-
- alias each_key each_name
-
- # Calls the block with each capitalized field name:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.each_capitalized_name do |key|
- # p key if key.start_with?('C')
- # end
- #
- # Output:
- #
- # "Content-Type"
- # "Connection"
- # "Cache-Control"
- # "Cf-Cache-Status"
- # "Cf-Ray"
- #
- # The capitalization is system-dependent;
- # see {Case Mapping}[https://docs.ruby-lang.org/en/master/case_mapping_rdoc.html].
- #
- # Returns an enumerator if no block is given.
- def each_capitalized_name #:yield: +key+
- block_given? or return enum_for(__method__) { @header.size }
- @header.each_key do |k|
- yield capitalize(k)
- end
- end
-
- # Calls the block with each string field value:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.each_value do |value|
- # p value if value.start_with?('c')
- # end
- #
- # Output:
- #
- # "chunked"
- # "cf-q-config;dur=6.0000002122251e-06"
- # "cloudflare"
- #
- # Returns an enumerator if no block is given.
- def each_value #:yield: +value+
- block_given? or return enum_for(__method__) { @header.size }
- @header.each_value do |va|
- yield va.join(', ')
- end
- end
-
- # Removes the header for the given case-insensitive +key+
- # (see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]);
- # returns the deleted value, or +nil+ if no such field exists:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.delete('Accept') # => ["*/*"]
- # req.delete('Nosuch') # => nil
- #
- def delete(key)
- @header.delete(key.downcase.to_s)
- end
-
- # Returns +true+ if the field for the case-insensitive +key+ exists, +false+ otherwise:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.key?('Accept') # => true
- # req.key?('Nosuch') # => false
- #
- def key?(key)
- @header.key?(key.downcase.to_s)
- end
-
- # Returns a hash of the key/value pairs:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.to_hash
- # # =>
- # {"accept-encoding"=>["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
- # "accept"=>["*/*"],
- # "user-agent"=>["Ruby"],
- # "host"=>["jsonplaceholder.typicode.com"]}
- #
- def to_hash
- @header.dup
- end
-
- # Like #each_header, but the keys are returned in capitalized form.
- #
- # Gem::Net::HTTPHeader#canonical_each is an alias for Gem::Net::HTTPHeader#each_capitalized.
- def each_capitalized
- block_given? or return enum_for(__method__) { @header.size }
- @header.each do |k,v|
- yield capitalize(k), v.join(', ')
- end
- end
-
- alias canonical_each each_capitalized
-
- def capitalize(name)
- name.to_s.split(/-/).map {|s| s.capitalize }.join('-')
- end
- private :capitalize
-
- # Returns an array of Range objects that represent
- # the value of field <tt>'Range'</tt>,
- # or +nil+ if there is no such field;
- # see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req['Range'] = 'bytes=0-99,200-299,400-499'
- # req.range # => [0..99, 200..299, 400..499]
- # req.delete('Range')
- # req.range # # => nil
- #
- def range
- return nil unless @header['range']
-
- value = self['Range']
- # byte-range-set = *( "," OWS ) ( byte-range-spec / suffix-byte-range-spec )
- # *( OWS "," [ OWS ( byte-range-spec / suffix-byte-range-spec ) ] )
- # corrected collected ABNF
- # http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-19#section-5.4.1
- # http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-19#appendix-C
- # http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-19#section-3.2.5
- unless /\Abytes=((?:,[ \t]*)*(?:\d+-\d*|-\d+)(?:[ \t]*,(?:[ \t]*\d+-\d*|-\d+)?)*)\z/ =~ value
- raise Gem::Net::HTTPHeaderSyntaxError, "invalid syntax for byte-ranges-specifier: '#{value}'"
- end
-
- byte_range_set = $1
- result = byte_range_set.split(/,/).map {|spec|
- m = /(\d+)?\s*-\s*(\d+)?/i.match(spec) or
- raise Gem::Net::HTTPHeaderSyntaxError, "invalid byte-range-spec: '#{spec}'"
- d1 = m[1].to_i
- d2 = m[2].to_i
- if m[1] and m[2]
- if d1 > d2
- raise Gem::Net::HTTPHeaderSyntaxError, "last-byte-pos MUST greater than or equal to first-byte-pos but '#{spec}'"
- end
- d1..d2
- elsif m[1]
- d1..-1
- elsif m[2]
- -d2..-1
- else
- raise Gem::Net::HTTPHeaderSyntaxError, 'range is not specified'
- end
- }
- # if result.empty?
- # byte-range-set must include at least one byte-range-spec or suffix-byte-range-spec
- # but above regexp already denies it.
- if result.size == 1 && result[0].begin == 0 && result[0].end == -1
- raise Gem::Net::HTTPHeaderSyntaxError, 'only one suffix-byte-range-spec with zero suffix-length'
- end
- result
- end
-
- # call-seq:
- # set_range(length) -> length
- # set_range(offset, length) -> range
- # set_range(begin..length) -> range
- #
- # Sets the value for field <tt>'Range'</tt>;
- # see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
- #
- # With argument +length+:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.set_range(100) # => 100
- # req['Range'] # => "bytes=0-99"
- #
- # With arguments +offset+ and +length+:
- #
- # req.set_range(100, 100) # => 100...200
- # req['Range'] # => "bytes=100-199"
- #
- # With argument +range+:
- #
- # req.set_range(100..199) # => 100..199
- # req['Range'] # => "bytes=100-199"
- #
- # Gem::Net::HTTPHeader#range= is an alias for Gem::Net::HTTPHeader#set_range.
- def set_range(r, e = nil)
- unless r
- @header.delete 'range'
- return r
- end
- r = (r...r+e) if e
- case r
- when Numeric
- n = r.to_i
- rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}")
- when Range
- first = r.first
- last = r.end
- last -= 1 if r.exclude_end?
- if last == -1
- rangestr = (first > 0 ? "#{first}-" : "-#{-first}")
- else
- raise Gem::Net::HTTPHeaderSyntaxError, 'range.first is negative' if first < 0
- raise Gem::Net::HTTPHeaderSyntaxError, 'range.last is negative' if last < 0
- raise Gem::Net::HTTPHeaderSyntaxError, 'must be .first < .last' if first > last
- rangestr = "#{first}-#{last}"
- end
- else
- raise TypeError, 'Range/Integer is required'
- end
- @header['range'] = ["bytes=#{rangestr}"]
- r
- end
-
- alias range= set_range
-
- # Returns the value of field <tt>'Content-Length'</tt> as an integer,
- # or +nil+ if there is no such field;
- # see {Content-Length request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-request-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/nosuch/1')
- # res.content_length # => 2
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.content_length # => nil
- #
- def content_length
- return nil unless key?('Content-Length')
- len = self['Content-Length'].slice(/\d+/) or
- raise Gem::Net::HTTPHeaderSyntaxError, 'wrong Content-Length format'
- len.to_i
- end
-
- # Sets the value of field <tt>'Content-Length'</tt> to the given numeric;
- # see {Content-Length response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-response-header]:
- #
- # _uri = uri.dup
- # hostname = _uri.hostname # => "jsonplaceholder.typicode.com"
- # _uri.path = '/posts' # => "/posts"
- # req = Gem::Net::HTTP::Post.new(_uri) # => #<Gem::Net::HTTP::Post POST>
- # req.body = '{"title": "foo","body": "bar","userId": 1}'
- # req.content_length = req.body.size # => 42
- # req.content_type = 'application/json'
- # res = Gem::Net::HTTP.start(hostname) do |http|
- # http.request(req)
- # end # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- def content_length=(len)
- unless len
- @header.delete 'content-length'
- return nil
- end
- @header['content-length'] = [len.to_i.to_s]
- end
-
- # Returns +true+ if field <tt>'Transfer-Encoding'</tt>
- # exists and has value <tt>'chunked'</tt>,
- # +false+ otherwise;
- # see {Transfer-Encoding response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#transfer-encoding-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['Transfer-Encoding'] # => "chunked"
- # res.chunked? # => true
- #
- def chunked?
- return false unless @header['transfer-encoding']
- field = self['Transfer-Encoding']
- (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
- end
-
- # Returns a Range object representing the value of field
- # <tt>'Content-Range'</tt>, or +nil+ if no such field exists;
- # see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['Content-Range'] # => nil
- # res['Content-Range'] = 'bytes 0-499/1000'
- # res['Content-Range'] # => "bytes 0-499/1000"
- # res.content_range # => 0..499
- #
- def content_range
- return nil unless @header['content-range']
- m = %r<\A\s*(\w+)\s+(\d+)-(\d+)/(\d+|\*)>.match(self['Content-Range']) or
- raise Gem::Net::HTTPHeaderSyntaxError, 'wrong Content-Range format'
- return unless m[1] == 'bytes'
- m[2].to_i .. m[3].to_i
- end
-
- # Returns the integer representing length of the value of field
- # <tt>'Content-Range'</tt>, or +nil+ if no such field exists;
- # see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['Content-Range'] # => nil
- # res['Content-Range'] = 'bytes 0-499/1000'
- # res.range_length # => 500
- #
- def range_length
- r = content_range() or return nil
- r.end - r.begin + 1
- end
-
- # Returns the {media type}[https://en.wikipedia.org/wiki/Media_type]
- # from the value of field <tt>'Content-Type'</tt>,
- # or +nil+ if no such field exists;
- # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['content-type'] # => "application/json; charset=utf-8"
- # res.content_type # => "application/json"
- #
- def content_type
- main = main_type()
- return nil unless main
-
- sub = sub_type()
- if sub
- "#{main}/#{sub}"
- else
- main
- end
- end
-
- # Returns the leading ('type') part of the
- # {media type}[https://en.wikipedia.org/wiki/Media_type]
- # from the value of field <tt>'Content-Type'</tt>,
- # or +nil+ if no such field exists;
- # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['content-type'] # => "application/json; charset=utf-8"
- # res.main_type # => "application"
- #
- def main_type
- return nil unless @header['content-type']
- self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
- end
-
- # Returns the trailing ('subtype') part of the
- # {media type}[https://en.wikipedia.org/wiki/Media_type]
- # from the value of field <tt>'Content-Type'</tt>,
- # or +nil+ if no such field exists;
- # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['content-type'] # => "application/json; charset=utf-8"
- # res.sub_type # => "json"
- #
- def sub_type
- return nil unless @header['content-type']
- _, sub = *self['Content-Type'].split(';').first.to_s.split('/')
- return nil unless sub
- sub.strip
- end
-
- # Returns the trailing ('parameters') part of the value of field <tt>'Content-Type'</tt>,
- # or +nil+ if no such field exists;
- # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['content-type'] # => "application/json; charset=utf-8"
- # res.type_params # => {"charset"=>"utf-8"}
- #
- def type_params
- result = {}
- list = self['Content-Type'].to_s.split(';')
- list.shift
- list.each do |param|
- k, v = *param.split('=', 2)
- result[k.strip] = v.strip
- end
- result
- end
-
- # Sets the value of field <tt>'Content-Type'</tt>;
- # returns the new value;
- # see {Content-Type request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-request-header]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.set_content_type('application/json') # => ["application/json"]
- #
- # Gem::Net::HTTPHeader#content_type= is an alias for Gem::Net::HTTPHeader#set_content_type.
- def set_content_type(type, params = {})
- @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
- end
-
- alias content_type= set_content_type
-
- # Sets the request body to a URL-encoded string derived from argument +params+,
- # and sets request header field <tt>'Content-Type'</tt>
- # to <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The resulting request is suitable for HTTP request +POST+ or +PUT+.
- #
- # Argument +params+ must be suitable for use as argument +enum+ to
- # {Gem::URI.encode_www_form}[https://docs.ruby-lang.org/en/master/Gem::URI.html#method-c-encode_www_form].
- #
- # With only argument +params+ given,
- # sets the body to a URL-encoded string with the default separator <tt>'&'</tt>:
- #
- # req = Gem::Net::HTTP::Post.new('example.com')
- #
- # req.set_form_data(q: 'ruby', lang: 'en')
- # req.body # => "q=ruby&lang=en"
- # req['Content-Type'] # => "application/x-www-form-urlencoded"
- #
- # req.set_form_data([['q', 'ruby'], ['lang', 'en']])
- # req.body # => "q=ruby&lang=en"
- #
- # req.set_form_data(q: ['ruby', 'perl'], lang: 'en')
- # req.body # => "q=ruby&q=perl&lang=en"
- #
- # req.set_form_data([['q', 'ruby'], ['q', 'perl'], ['lang', 'en']])
- # req.body # => "q=ruby&q=perl&lang=en"
- #
- # With string argument +sep+ also given,
- # uses that string as the separator:
- #
- # req.set_form_data({q: 'ruby', lang: 'en'}, '|')
- # req.body # => "q=ruby|lang=en"
- #
- # Gem::Net::HTTPHeader#form_data= is an alias for Gem::Net::HTTPHeader#set_form_data.
- def set_form_data(params, sep = '&')
- query = Gem::URI.encode_www_form(params)
- query.gsub!(/&/, sep) if sep != '&'
- self.body = query
- self.content_type = 'application/x-www-form-urlencoded'
- end
-
- alias form_data= set_form_data
-
- # Stores form data to be used in a +POST+ or +PUT+ request.
- #
- # The form data given in +params+ consists of zero or more fields;
- # each field is:
- #
- # - A scalar value.
- # - A name/value pair.
- # - An IO stream opened for reading.
- #
- # Argument +params+ should be an
- # {Enumerable}[https://docs.ruby-lang.org/en/master/Enumerable.html#module-Enumerable-label-Enumerable+in+Ruby+Classes]
- # (method <tt>params.map</tt> will be called),
- # and is often an array or hash.
- #
- # First, we set up a request:
- #
- # _uri = uri.dup
- # _uri.path ='/posts'
- # req = Gem::Net::HTTP::Post.new(_uri)
- #
- # <b>Argument +params+ As an Array</b>
- #
- # When +params+ is an array,
- # each of its elements is a subarray that defines a field;
- # the subarray may contain:
- #
- # - One string:
- #
- # req.set_form([['foo'], ['bar'], ['baz']])
- #
- # - Two strings:
- #
- # req.set_form([%w[foo 0], %w[bar 1], %w[baz 2]])
- #
- # - When argument +enctype+ (see below) is given as
- # <tt>'multipart/form-data'</tt>:
- #
- # - A string name and an IO stream opened for reading:
- #
- # require 'stringio'
- # req.set_form([['file', StringIO.new('Ruby is cool.')]])
- #
- # - A string name, an IO stream opened for reading,
- # and an options hash, which may contain these entries:
- #
- # - +:filename+: The name of the file to use.
- # - +:content_type+: The content type of the uploaded file.
- #
- # Example:
- #
- # req.set_form([['file', file, {filename: "other-filename.foo"}]]
- #
- # The various forms may be mixed:
- #
- # req.set_form(['foo', %w[bar 1], ['file', file]])
- #
- # <b>Argument +params+ As a Hash</b>
- #
- # When +params+ is a hash,
- # each of its entries is a name/value pair that defines a field:
- #
- # - The name is a string.
- # - The value may be:
- #
- # - +nil+.
- # - Another string.
- # - An IO stream opened for reading
- # (only when argument +enctype+ -- see below -- is given as
- # <tt>'multipart/form-data'</tt>).
- #
- # Examples:
- #
- # # Nil-valued fields.
- # req.set_form({'foo' => nil, 'bar' => nil, 'baz' => nil})
- #
- # # String-valued fields.
- # req.set_form({'foo' => 0, 'bar' => 1, 'baz' => 2})
- #
- # # IO-valued field.
- # require 'stringio'
- # req.set_form({'file' => StringIO.new('Ruby is cool.')})
- #
- # # Mixture of fields.
- # req.set_form({'foo' => nil, 'bar' => 1, 'file' => file})
- #
- # Optional argument +enctype+ specifies the value to be given
- # to field <tt>'Content-Type'</tt>, and must be one of:
- #
- # - <tt>'application/x-www-form-urlencoded'</tt> (the default).
- # - <tt>'multipart/form-data'</tt>;
- # see {RFC 7578}[https://www.rfc-editor.org/rfc/rfc7578].
- #
- # Optional argument +formopt+ is a hash of options
- # (applicable only when argument +enctype+
- # is <tt>'multipart/form-data'</tt>)
- # that may include the following entries:
- #
- # - +:boundary+: The value is the boundary string for the multipart message.
- # If not given, the boundary is a random string.
- # See {Boundary}[https://www.rfc-editor.org/rfc/rfc7578#section-4.1].
- # - +:charset+: Value is the character set for the form submission.
- # Field names and values of non-file fields should be encoded with this charset.
- #
- def set_form(params, enctype='application/x-www-form-urlencoded', formopt={})
- @body_data = params
- @body = nil
- @body_stream = nil
- @form_option = formopt
- case enctype
- when /\Aapplication\/x-www-form-urlencoded\z/i,
- /\Amultipart\/form-data\z/i
- self.content_type = enctype
- else
- raise ArgumentError, "invalid enctype: #{enctype}"
- end
- end
-
- # Sets header <tt>'Authorization'</tt> using the given
- # +account+ and +password+ strings:
- #
- # req.basic_auth('my_account', 'my_password')
- # req['Authorization']
- # # => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
- #
- def basic_auth(account, password)
- @header['authorization'] = [basic_encode(account, password)]
- end
-
- # Sets header <tt>'Proxy-Authorization'</tt> using the given
- # +account+ and +password+ strings:
- #
- # req.proxy_basic_auth('my_account', 'my_password')
- # req['Proxy-Authorization']
- # # => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
- #
- def proxy_basic_auth(account, password)
- @header['proxy-authorization'] = [basic_encode(account, password)]
- end
-
- def basic_encode(account, password)
- 'Basic ' + ["#{account}:#{password}"].pack('m0')
- end
- private :basic_encode
-
-# Returns whether the HTTP session is to be closed.
- def connection_close?
- token = /(?:\A|,)\s*close\s*(?:\z|,)/i
- @header['connection']&.grep(token) {return true}
- @header['proxy-connection']&.grep(token) {return true}
- false
- end
-
-# Returns whether the HTTP session is to be kept alive.
- def connection_keep_alive?
- token = /(?:\A|,)\s*keep-alive\s*(?:\z|,)/i
- @header['connection']&.grep(token) {return true}
- @header['proxy-connection']&.grep(token) {return true}
- false
- end
-
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/proxy_delta.rb b/lib/rubygems/vendor/net-http/lib/net/http/proxy_delta.rb
deleted file mode 100644
index 137295a883..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/proxy_delta.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-module Gem::Net::HTTP::ProxyDelta #:nodoc: internal use only
- private
-
- def conn_address
- proxy_address()
- end
-
- def conn_port
- proxy_port()
- end
-
- def edit_path(path)
- use_ssl? ? path : "http://#{addr_port()}#{path}"
- end
-end
-
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/request.rb b/lib/rubygems/vendor/net-http/lib/net/http/request.rb
deleted file mode 100644
index 495ec9be54..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/request.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-
-# This class is the base class for \Gem::Net::HTTP request classes.
-# The class should not be used directly;
-# instead you should use its subclasses, listed below.
-#
-# == Creating a Request
-#
-# An request object may be created with either a Gem::URI or a string hostname:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('https://jsonplaceholder.typicode.com/')
-# req = Gem::Net::HTTP::Get.new(uri) # => #<Gem::Net::HTTP::Get GET>
-# req = Gem::Net::HTTP::Get.new(uri.hostname) # => #<Gem::Net::HTTP::Get GET>
-#
-# And with any of the subclasses:
-#
-# req = Gem::Net::HTTP::Head.new(uri) # => #<Gem::Net::HTTP::Head HEAD>
-# req = Gem::Net::HTTP::Post.new(uri) # => #<Gem::Net::HTTP::Post POST>
-# req = Gem::Net::HTTP::Put.new(uri) # => #<Gem::Net::HTTP::Put PUT>
-# # ...
-#
-# The new instance is suitable for use as the argument to Gem::Net::HTTP#request.
-#
-# == Request Headers
-#
-# A new request object has these header fields by default:
-#
-# req.to_hash
-# # =>
-# {"accept-encoding"=>["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
-# "accept"=>["*/*"],
-# "user-agent"=>["Ruby"],
-# "host"=>["jsonplaceholder.typicode.com"]}
-#
-# See:
-#
-# - {Request header Accept-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Accept-Encoding]
-# and {Compression and Decompression}[rdoc-ref:Gem::Net::HTTP@Compression+and+Decompression].
-# - {Request header Accept}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#accept-request-header].
-# - {Request header User-Agent}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#user-agent-request-header].
-# - {Request header Host}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#host-request-header].
-#
-# You can add headers or override default headers:
-#
-# # res = Gem::Net::HTTP::Get.new(uri, {'foo' => '0', 'bar' => '1'})
-#
-# This class (and therefore its subclasses) also includes (indirectly)
-# module Gem::Net::HTTPHeader, which gives access to its
-# {methods for setting headers}[rdoc-ref:Gem::Net::HTTPHeader@Setters].
-#
-# == Request Subclasses
-#
-# Subclasses for HTTP requests:
-#
-# - Gem::Net::HTTP::Get
-# - Gem::Net::HTTP::Head
-# - Gem::Net::HTTP::Post
-# - Gem::Net::HTTP::Put
-# - Gem::Net::HTTP::Delete
-# - Gem::Net::HTTP::Options
-# - Gem::Net::HTTP::Trace
-# - Gem::Net::HTTP::Patch
-#
-# Subclasses for WebDAV requests:
-#
-# - Gem::Net::HTTP::Propfind
-# - Gem::Net::HTTP::Proppatch
-# - Gem::Net::HTTP::Mkcol
-# - Gem::Net::HTTP::Copy
-# - Gem::Net::HTTP::Move
-# - Gem::Net::HTTP::Lock
-# - Gem::Net::HTTP::Unlock
-#
-class Gem::Net::HTTPRequest < Gem::Net::HTTPGenericRequest
- # Creates an HTTP request object for +path+.
- #
- # +initheader+ are the default headers to use. Gem::Net::HTTP adds
- # Accept-Encoding to enable compression of the response body unless
- # Accept-Encoding or Range are supplied in +initheader+.
-
- def initialize(path, initheader = nil)
- super self.class::METHOD,
- self.class::REQUEST_HAS_BODY,
- self.class::RESPONSE_HAS_BODY,
- path, initheader
- end
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/requests.rb b/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
deleted file mode 100644
index 1a57ddc7c2..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
+++ /dev/null
@@ -1,425 +0,0 @@
-# frozen_string_literal: true
-
-# HTTP/1.1 methods --- RFC2616
-
-# \Class for representing
-# {HTTP method GET}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#GET_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Get.new(uri) # => #<Gem::Net::HTTP::Get GET>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: optional.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
-#
-# Related:
-#
-# - Gem::Net::HTTP.get: sends +GET+ request, returns response body.
-# - Gem::Net::HTTP#get: sends +GET+ request, returns response object.
-#
-class Gem::Net::HTTP::Get < Gem::Net::HTTPRequest
- METHOD = 'GET'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method HEAD}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#HEAD_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Head.new(uri) # => #<Gem::Net::HTTP::Head HEAD>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: optional.
-# - Response body: no.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
-#
-# Related:
-#
-# - Gem::Net::HTTP#head: sends +HEAD+ request, returns response object.
-#
-class Gem::Net::HTTP::Head < Gem::Net::HTTPRequest
- METHOD = 'HEAD'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = false
-end
-
-# \Class for representing
-# {HTTP method POST}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#POST_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# uri.path = '/posts'
-# req = Gem::Net::HTTP::Post.new(uri) # => #<Gem::Net::HTTP::Post POST>
-# req.body = '{"title": "foo","body": "bar","userId": 1}'
-# req.content_type = 'application/json'
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: yes.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
-#
-# Related:
-#
-# - Gem::Net::HTTP.post: sends +POST+ request, returns response object.
-# - Gem::Net::HTTP#post: sends +POST+ request, returns response object.
-#
-class Gem::Net::HTTP::Post < Gem::Net::HTTPRequest
- METHOD = 'POST'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method PUT}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#PUT_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# uri.path = '/posts'
-# req = Gem::Net::HTTP::Put.new(uri) # => #<Gem::Net::HTTP::Put PUT>
-# req.body = '{"title": "foo","body": "bar","userId": 1}'
-# req.content_type = 'application/json'
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: yes.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-class Gem::Net::HTTP::Put < Gem::Net::HTTPRequest
- METHOD = 'PUT'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method DELETE}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#DELETE_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# uri.path = '/posts/1'
-# req = Gem::Net::HTTP::Delete.new(uri) # => #<Gem::Net::HTTP::Delete DELETE>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: optional.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-# Related:
-#
-# - Gem::Net::HTTP#delete: sends +DELETE+ request, returns response object.
-#
-class Gem::Net::HTTP::Delete < Gem::Net::HTTPRequest
- METHOD = 'DELETE'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method OPTIONS}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#OPTIONS_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Options.new(uri) # => #<Gem::Net::HTTP::Options OPTIONS>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: optional.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-# Related:
-#
-# - Gem::Net::HTTP#options: sends +OPTIONS+ request, returns response object.
-#
-class Gem::Net::HTTP::Options < Gem::Net::HTTPRequest
- METHOD = 'OPTIONS'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method TRACE}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#TRACE_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Trace.new(uri) # => #<Gem::Net::HTTP::Trace TRACE>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: no.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-# Related:
-#
-# - Gem::Net::HTTP#trace: sends +TRACE+ request, returns response object.
-#
-class Gem::Net::HTTP::Trace < Gem::Net::HTTPRequest
- METHOD = 'TRACE'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method PATCH}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#PATCH_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# uri.path = '/posts'
-# req = Gem::Net::HTTP::Patch.new(uri) # => #<Gem::Net::HTTP::Patch PATCH>
-# req.body = '{"title": "foo","body": "bar","userId": 1}'
-# req.content_type = 'application/json'
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: yes.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-# Related:
-#
-# - Gem::Net::HTTP#patch: sends +PATCH+ request, returns response object.
-#
-class Gem::Net::HTTP::Patch < Gem::Net::HTTPRequest
- METHOD = 'PATCH'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-#
-# WebDAV methods --- RFC2518
-#
-
-# \Class for representing
-# {WebDAV method PROPFIND}[http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Propfind.new(uri) # => #<Gem::Net::HTTP::Propfind PROPFIND>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#propfind: sends +PROPFIND+ request, returns response object.
-#
-class Gem::Net::HTTP::Propfind < Gem::Net::HTTPRequest
- METHOD = 'PROPFIND'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method PROPPATCH}[http://www.webdav.org/specs/rfc4918.html#METHOD_PROPPATCH]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Proppatch.new(uri) # => #<Gem::Net::HTTP::Proppatch PROPPATCH>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#proppatch: sends +PROPPATCH+ request, returns response object.
-#
-class Gem::Net::HTTP::Proppatch < Gem::Net::HTTPRequest
- METHOD = 'PROPPATCH'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method MKCOL}[http://www.webdav.org/specs/rfc4918.html#METHOD_MKCOL]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Mkcol.new(uri) # => #<Gem::Net::HTTP::Mkcol MKCOL>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#mkcol: sends +MKCOL+ request, returns response object.
-#
-class Gem::Net::HTTP::Mkcol < Gem::Net::HTTPRequest
- METHOD = 'MKCOL'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method COPY}[http://www.webdav.org/specs/rfc4918.html#METHOD_COPY]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Copy.new(uri) # => #<Gem::Net::HTTP::Copy COPY>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#copy: sends +COPY+ request, returns response object.
-#
-class Gem::Net::HTTP::Copy < Gem::Net::HTTPRequest
- METHOD = 'COPY'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method MOVE}[http://www.webdav.org/specs/rfc4918.html#METHOD_MOVE]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Move.new(uri) # => #<Gem::Net::HTTP::Move MOVE>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#move: sends +MOVE+ request, returns response object.
-#
-class Gem::Net::HTTP::Move < Gem::Net::HTTPRequest
- METHOD = 'MOVE'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method LOCK}[http://www.webdav.org/specs/rfc4918.html#METHOD_LOCK]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Lock.new(uri) # => #<Gem::Net::HTTP::Lock LOCK>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#lock: sends +LOCK+ request, returns response object.
-#
-class Gem::Net::HTTP::Lock < Gem::Net::HTTPRequest
- METHOD = 'LOCK'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method UNLOCK}[http://www.webdav.org/specs/rfc4918.html#METHOD_UNLOCK]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Unlock.new(uri) # => #<Gem::Net::HTTP::Unlock UNLOCK>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#unlock: sends +UNLOCK+ request, returns response object.
-#
-class Gem::Net::HTTP::Unlock < Gem::Net::HTTPRequest
- METHOD = 'UNLOCK'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/response.rb b/lib/rubygems/vendor/net-http/lib/net/http/response.rb
deleted file mode 100644
index cbbd191d87..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/response.rb
+++ /dev/null
@@ -1,738 +0,0 @@
-# frozen_string_literal: true
-
-# This class is the base class for \Gem::Net::HTTP response classes.
-#
-# == About the Examples
-#
-# :include: doc/net-http/examples.rdoc
-#
-# == Returned Responses
-#
-# \Method Gem::Net::HTTP.get_response returns
-# an instance of one of the subclasses of \Gem::Net::HTTPResponse:
-#
-# Gem::Net::HTTP.get_response(uri)
-# # => #<Gem::Net::HTTPOK 200 OK readbody=true>
-# Gem::Net::HTTP.get_response(hostname, '/nosuch')
-# # => #<Gem::Net::HTTPNotFound 404 Not Found readbody=true>
-#
-# As does method Gem::Net::HTTP#request:
-#
-# req = Gem::Net::HTTP::Get.new(uri)
-# Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
-#
-# \Class \Gem::Net::HTTPResponse includes module Gem::Net::HTTPHeader,
-# which provides access to response header values via (among others):
-#
-# - \Hash-like method <tt>[]</tt>.
-# - Specific reader methods, such as +content_type+.
-#
-# Examples:
-#
-# res = Gem::Net::HTTP.get_response(uri) # => #<Gem::Net::HTTPOK 200 OK readbody=true>
-# res['Content-Type'] # => "text/html; charset=UTF-8"
-# res.content_type # => "text/html"
-#
-# == Response Subclasses
-#
-# \Class \Gem::Net::HTTPResponse has a subclass for each
-# {HTTP status code}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes].
-# You can look up the response class for a given code:
-#
-# Gem::Net::HTTPResponse::CODE_TO_OBJ['200'] # => Gem::Net::HTTPOK
-# Gem::Net::HTTPResponse::CODE_TO_OBJ['400'] # => Gem::Net::HTTPBadRequest
-# Gem::Net::HTTPResponse::CODE_TO_OBJ['404'] # => Gem::Net::HTTPNotFound
-#
-# And you can retrieve the status code for a response object:
-#
-# Gem::Net::HTTP.get_response(uri).code # => "200"
-# Gem::Net::HTTP.get_response(hostname, '/nosuch').code # => "404"
-#
-# The response subclasses (indentation shows class hierarchy):
-#
-# - Gem::Net::HTTPUnknownResponse (for unhandled \HTTP extensions).
-#
-# - Gem::Net::HTTPInformation:
-#
-# - Gem::Net::HTTPContinue (100)
-# - Gem::Net::HTTPSwitchProtocol (101)
-# - Gem::Net::HTTPProcessing (102)
-# - Gem::Net::HTTPEarlyHints (103)
-#
-# - Gem::Net::HTTPSuccess:
-#
-# - Gem::Net::HTTPOK (200)
-# - Gem::Net::HTTPCreated (201)
-# - Gem::Net::HTTPAccepted (202)
-# - Gem::Net::HTTPNonAuthoritativeInformation (203)
-# - Gem::Net::HTTPNoContent (204)
-# - Gem::Net::HTTPResetContent (205)
-# - Gem::Net::HTTPPartialContent (206)
-# - Gem::Net::HTTPMultiStatus (207)
-# - Gem::Net::HTTPAlreadyReported (208)
-# - Gem::Net::HTTPIMUsed (226)
-#
-# - Gem::Net::HTTPRedirection:
-#
-# - Gem::Net::HTTPMultipleChoices (300)
-# - Gem::Net::HTTPMovedPermanently (301)
-# - Gem::Net::HTTPFound (302)
-# - Gem::Net::HTTPSeeOther (303)
-# - Gem::Net::HTTPNotModified (304)
-# - Gem::Net::HTTPUseProxy (305)
-# - Gem::Net::HTTPTemporaryRedirect (307)
-# - Gem::Net::HTTPPermanentRedirect (308)
-#
-# - Gem::Net::HTTPClientError:
-#
-# - Gem::Net::HTTPBadRequest (400)
-# - Gem::Net::HTTPUnauthorized (401)
-# - Gem::Net::HTTPPaymentRequired (402)
-# - Gem::Net::HTTPForbidden (403)
-# - Gem::Net::HTTPNotFound (404)
-# - Gem::Net::HTTPMethodNotAllowed (405)
-# - Gem::Net::HTTPNotAcceptable (406)
-# - Gem::Net::HTTPProxyAuthenticationRequired (407)
-# - Gem::Net::HTTPRequestTimeOut (408)
-# - Gem::Net::HTTPConflict (409)
-# - Gem::Net::HTTPGone (410)
-# - Gem::Net::HTTPLengthRequired (411)
-# - Gem::Net::HTTPPreconditionFailed (412)
-# - Gem::Net::HTTPRequestEntityTooLarge (413)
-# - Gem::Net::HTTPRequestURITooLong (414)
-# - Gem::Net::HTTPUnsupportedMediaType (415)
-# - Gem::Net::HTTPRequestedRangeNotSatisfiable (416)
-# - Gem::Net::HTTPExpectationFailed (417)
-# - Gem::Net::HTTPMisdirectedRequest (421)
-# - Gem::Net::HTTPUnprocessableEntity (422)
-# - Gem::Net::HTTPLocked (423)
-# - Gem::Net::HTTPFailedDependency (424)
-# - Gem::Net::HTTPUpgradeRequired (426)
-# - Gem::Net::HTTPPreconditionRequired (428)
-# - Gem::Net::HTTPTooManyRequests (429)
-# - Gem::Net::HTTPRequestHeaderFieldsTooLarge (431)
-# - Gem::Net::HTTPUnavailableForLegalReasons (451)
-#
-# - Gem::Net::HTTPServerError:
-#
-# - Gem::Net::HTTPInternalServerError (500)
-# - Gem::Net::HTTPNotImplemented (501)
-# - Gem::Net::HTTPBadGateway (502)
-# - Gem::Net::HTTPServiceUnavailable (503)
-# - Gem::Net::HTTPGatewayTimeOut (504)
-# - Gem::Net::HTTPVersionNotSupported (505)
-# - Gem::Net::HTTPVariantAlsoNegotiates (506)
-# - Gem::Net::HTTPInsufficientStorage (507)
-# - Gem::Net::HTTPLoopDetected (508)
-# - Gem::Net::HTTPNotExtended (510)
-# - Gem::Net::HTTPNetworkAuthenticationRequired (511)
-#
-# There is also the Gem::Net::HTTPBadResponse exception which is raised when
-# there is a protocol error.
-#
-class Gem::Net::HTTPResponse
- class << self
- # true if the response has a body.
- def body_permitted?
- self::HAS_BODY
- end
-
- def exception_type # :nodoc: internal use only
- self::EXCEPTION_TYPE
- end
-
- def read_new(sock) #:nodoc: internal use only
- httpv, code, msg = read_status_line(sock)
- res = response_class(code).new(httpv, code, msg)
- each_response_header(sock) do |k,v|
- res.add_field k, v
- end
- res
- end
-
- private
-
- def read_status_line(sock)
- str = sock.readline
- m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)(?:\s+(.*))?\z/in.match(str) or
- raise Gem::Net::HTTPBadResponse, "wrong status line: #{str.dump}"
- m.captures
- end
-
- def response_class(code)
- CODE_TO_OBJ[code] or
- CODE_CLASS_TO_OBJ[code[0,1]] or
- Gem::Net::HTTPUnknownResponse
- end
-
- def each_response_header(sock)
- key = value = nil
- while true
- line = sock.readuntil("\n", true).sub(/\s+\z/, '')
- break if line.empty?
- if line[0] == ?\s or line[0] == ?\t and value
- value << ' ' unless value.empty?
- value << line.strip
- else
- yield key, value if key
- key, value = line.strip.split(/\s*:\s*/, 2)
- raise Gem::Net::HTTPBadResponse, 'wrong header line format' if value.nil?
- end
- end
- yield key, value if key
- end
- end
-
- # next is to fix bug in RDoc, where the private inside class << self
- # spills out.
- public
-
- include Gem::Net::HTTPHeader
-
- def initialize(httpv, code, msg) #:nodoc: internal use only
- @http_version = httpv
- @code = code
- @message = msg
- initialize_http_header nil
- @body = nil
- @read = false
- @uri = nil
- @decode_content = false
- @body_encoding = false
- @ignore_eof = true
- end
-
- # The HTTP version supported by the server.
- attr_reader :http_version
-
- # The HTTP result code string. For example, '302'. You can also
- # determine the response type by examining which response subclass
- # the response object is an instance of.
- attr_reader :code
-
- # The HTTP result message sent by the server. For example, 'Not Found'.
- attr_reader :message
- alias msg message # :nodoc: obsolete
-
- # The Gem::URI used to fetch this response. The response Gem::URI is only available
- # if a Gem::URI was used to create the request.
- attr_reader :uri
-
- # Set to true automatically when the request did not contain an
- # Accept-Encoding header from the user.
- attr_accessor :decode_content
-
- # Returns the value set by body_encoding=, or +false+ if none;
- # see #body_encoding=.
- attr_reader :body_encoding
-
- # Sets the encoding that should be used when reading the body:
- #
- # - If the given value is an Encoding object, that encoding will be used.
- # - Otherwise if the value is a string, the value of
- # {Encoding#find(value)}[https://docs.ruby-lang.org/en/master/Encoding.html#method-c-find]
- # will be used.
- # - Otherwise an encoding will be deduced from the body itself.
- #
- # Examples:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # req = Gem::Net::HTTP::Get.new('/')
- #
- # http.request(req) do |res|
- # p res.body.encoding # => #<Encoding:ASCII-8BIT>
- # end
- #
- # http.request(req) do |res|
- # res.body_encoding = "UTF-8"
- # p res.body.encoding # => #<Encoding:UTF-8>
- # end
- #
- def body_encoding=(value)
- value = Encoding.find(value) if value.is_a?(String)
- @body_encoding = value
- end
-
- # Whether to ignore EOF when reading bodies with a specified Content-Length
- # header.
- attr_accessor :ignore_eof
-
- def inspect
- "#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
- end
-
- #
- # response <-> exception relationship
- #
-
- def code_type #:nodoc:
- self.class
- end
-
- def error! #:nodoc:
- message = @code
- message = "#{message} #{@message.dump}" if @message
- raise error_type().new(message, self)
- end
-
- def error_type #:nodoc:
- self.class::EXCEPTION_TYPE
- end
-
- # Raises an HTTP error if the response is not 2xx (success).
- def value
- error! unless self.kind_of?(Gem::Net::HTTPSuccess)
- end
-
- def uri= uri # :nodoc:
- @uri = uri.dup if uri
- end
-
- #
- # header (for backward compatibility only; DO NOT USE)
- #
-
- def response #:nodoc:
- warn "Gem::Net::HTTPResponse#response is obsolete", uplevel: 1 if $VERBOSE
- self
- end
-
- def header #:nodoc:
- warn "Gem::Net::HTTPResponse#header is obsolete", uplevel: 1 if $VERBOSE
- self
- end
-
- def read_header #:nodoc:
- warn "Gem::Net::HTTPResponse#read_header is obsolete", uplevel: 1 if $VERBOSE
- self
- end
-
- #
- # body
- #
-
- def reading_body(sock, reqmethodallowbody) #:nodoc: internal use only
- @socket = sock
- @body_exist = reqmethodallowbody && self.class.body_permitted?
- begin
- yield
- self.body # ensure to read body
- ensure
- @socket = nil
- end
- end
-
- # Gets the entity body returned by the remote HTTP server.
- #
- # If a block is given, the body is passed to the block, and
- # the body is provided in fragments, as it is read in from the socket.
- #
- # If +dest+ argument is given, response is read into that variable,
- # with <code>dest#<<</code> method (it could be String or IO, or any
- # other object responding to <code><<</code>).
- #
- # Calling this method a second or subsequent time for the same
- # HTTPResponse object will return the value already read.
- #
- # http.request_get('/index.html') {|res|
- # puts res.read_body
- # }
- #
- # http.request_get('/index.html') {|res|
- # p res.read_body.object_id # 538149362
- # p res.read_body.object_id # 538149362
- # }
- #
- # # using iterator
- # http.request_get('/index.html') {|res|
- # res.read_body do |segment|
- # print segment
- # end
- # }
- #
- def read_body(dest = nil, &block)
- if @read
- raise IOError, "#{self.class}\#read_body called twice" if dest or block
- return @body
- end
- to = procdest(dest, block)
- stream_check
- if @body_exist
- read_body_0 to
- @body = to
- else
- @body = nil
- end
- @read = true
- return if @body.nil?
-
- case enc = @body_encoding
- when Encoding, false, nil
- # Encoding: force given encoding
- # false/nil: do not force encoding
- else
- # other value: detect encoding from body
- enc = detect_encoding(@body)
- end
-
- @body.force_encoding(enc) if enc
-
- @body
- end
-
- # Returns the string response body;
- # note that repeated calls for the unmodified body return a cached string:
- #
- # path = '/todos/1'
- # Gem::Net::HTTP.start(hostname) do |http|
- # res = http.get(path)
- # p res.body
- # p http.head(path).body # No body.
- # end
- #
- # Output:
- #
- # "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n}"
- # nil
- #
- def body
- read_body()
- end
-
- # Sets the body of the response to the given value.
- def body=(value)
- @body = value
- end
-
- alias entity body #:nodoc: obsolete
-
- private
-
- # :nodoc:
- def detect_encoding(str, encoding=nil)
- if encoding
- elsif encoding = type_params['charset']
- elsif encoding = check_bom(str)
- else
- encoding = case content_type&.downcase
- when %r{text/x(?:ht)?ml|application/(?:[^+]+\+)?xml}
- /\A<xml[ \t\r\n]+
- version[ \t\r\n]*=[ \t\r\n]*(?:"[0-9.]+"|'[0-9.]*')[ \t\r\n]+
- encoding[ \t\r\n]*=[ \t\r\n]*
- (?:"([A-Za-z][\-A-Za-z0-9._]*)"|'([A-Za-z][\-A-Za-z0-9._]*)')/x =~ str
- encoding = $1 || $2 || Encoding::UTF_8
- when %r{text/html.*}
- sniff_encoding(str)
- end
- end
- return encoding
- end
-
- # :nodoc:
- def sniff_encoding(str, encoding=nil)
- # the encoding sniffing algorithm
- # http://www.w3.org/TR/html5/parsing.html#determining-the-character-encoding
- if enc = scanning_meta(str)
- enc
- # 6. last visited page or something
- # 7. frequency
- elsif str.ascii_only?
- Encoding::US_ASCII
- elsif str.dup.force_encoding(Encoding::UTF_8).valid_encoding?
- Encoding::UTF_8
- end
- # 8. implementation-defined or user-specified
- end
-
- # :nodoc:
- def check_bom(str)
- case str.byteslice(0, 2)
- when "\xFE\xFF"
- return Encoding::UTF_16BE
- when "\xFF\xFE"
- return Encoding::UTF_16LE
- end
- if "\xEF\xBB\xBF" == str.byteslice(0, 3)
- return Encoding::UTF_8
- end
- nil
- end
-
- # :nodoc:
- def scanning_meta(str)
- require 'strscan'
- ss = StringScanner.new(str)
- if ss.scan_until(/<meta[\t\n\f\r ]*/)
- attrs = {} # attribute_list
- got_pragma = false
- need_pragma = nil
- charset = nil
-
- # step: Attributes
- while attr = get_attribute(ss)
- name, value = *attr
- next if attrs[name]
- attrs[name] = true
- case name
- when 'http-equiv'
- got_pragma = true if value == 'content-type'
- when 'content'
- encoding = extracting_encodings_from_meta_elements(value)
- unless charset
- charset = encoding
- end
- need_pragma = true
- when 'charset'
- need_pragma = false
- charset = value
- end
- end
-
- # step: Processing
- return if need_pragma.nil?
- return if need_pragma && !got_pragma
-
- charset = Encoding.find(charset) rescue nil
- return unless charset
- charset = Encoding::UTF_8 if charset == Encoding::UTF_16
- return charset # tentative
- end
- nil
- end
-
- def get_attribute(ss)
- ss.scan(/[\t\n\f\r \/]*/)
- if ss.peek(1) == '>'
- ss.getch
- return nil
- end
- name = ss.scan(/[^=\t\n\f\r \/>]*/)
- name.downcase!
- raise if name.empty?
- ss.skip(/[\t\n\f\r ]*/)
- if ss.getch != '='
- value = ''
- return [name, value]
- end
- ss.skip(/[\t\n\f\r ]*/)
- case ss.peek(1)
- when '"'
- ss.getch
- value = ss.scan(/[^"]+/)
- value.downcase!
- ss.getch
- when "'"
- ss.getch
- value = ss.scan(/[^']+/)
- value.downcase!
- ss.getch
- when '>'
- value = ''
- else
- value = ss.scan(/[^\t\n\f\r >]+/)
- value.downcase!
- end
- [name, value]
- end
-
- def extracting_encodings_from_meta_elements(value)
- # http://dev.w3.org/html5/spec/fetching-resources.html#algorithm-for-extracting-an-encoding-from-a-meta-element
- if /charset[\t\n\f\r ]*=(?:"([^"]*)"|'([^']*)'|["']|\z|([^\t\n\f\r ;]+))/i =~ value
- return $1 || $2 || $3
- end
- return nil
- end
-
- ##
- # Checks for a supported Content-Encoding header and yields an Inflate
- # wrapper for this response's socket when zlib is present. If the
- # Content-Encoding is not supported or zlib is missing, the plain socket is
- # yielded.
- #
- # If a Content-Range header is present, a plain socket is yielded as the
- # bytes in the range may not be a complete deflate block.
-
- def inflater # :nodoc:
- return yield @socket unless Gem::Net::HTTP::HAVE_ZLIB
- return yield @socket unless @decode_content
- return yield @socket if self['content-range']
-
- v = self['content-encoding']
- case v&.downcase
- when 'deflate', 'gzip', 'x-gzip' then
- self.delete 'content-encoding'
-
- inflate_body_io = Inflater.new(@socket)
-
- begin
- yield inflate_body_io
- success = true
- ensure
- begin
- inflate_body_io.finish
- if self['content-length']
- self['content-length'] = inflate_body_io.bytes_inflated.to_s
- end
- rescue => err
- # Ignore #finish's error if there is an exception from yield
- raise err if success
- end
- end
- when 'none', 'identity' then
- self.delete 'content-encoding'
-
- yield @socket
- else
- yield @socket
- end
- end
-
- def read_body_0(dest)
- inflater do |inflate_body_io|
- if chunked?
- read_chunked dest, inflate_body_io
- return
- end
-
- @socket = inflate_body_io
-
- clen = content_length()
- if clen
- @socket.read clen, dest, @ignore_eof
- return
- end
- clen = range_length()
- if clen
- @socket.read clen, dest
- return
- end
- @socket.read_all dest
- end
- end
-
- ##
- # read_chunked reads from +@socket+ for chunk-size, chunk-extension, CRLF,
- # etc. and +chunk_data_io+ for chunk-data which may be deflate or gzip
- # encoded.
- #
- # See RFC 2616 section 3.6.1 for definitions
-
- def read_chunked(dest, chunk_data_io) # :nodoc:
- total = 0
- while true
- line = @socket.readline
- hexlen = line.slice(/[0-9a-fA-F]+/) or
- raise Gem::Net::HTTPBadResponse, "wrong chunk size line: #{line}"
- len = hexlen.hex
- break if len == 0
- begin
- chunk_data_io.read len, dest
- ensure
- total += len
- @socket.read 2 # \r\n
- end
- end
- until @socket.readline.empty?
- # none
- end
- end
-
- def stream_check
- raise IOError, 'attempt to read body out of block' if @socket.nil? || @socket.closed?
- end
-
- def procdest(dest, block)
- raise ArgumentError, 'both arg and block given for HTTP method' if
- dest and block
- if block
- Gem::Net::ReadAdapter.new(block)
- else
- dest || +''
- end
- end
-
- ##
- # Inflater is a wrapper around Gem::Net::BufferedIO that transparently inflates
- # zlib and gzip streams.
-
- class Inflater # :nodoc:
-
- ##
- # Creates a new Inflater wrapping +socket+
-
- def initialize socket
- @socket = socket
- # zlib with automatic gzip detection
- @inflate = Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
- end
-
- ##
- # Finishes the inflate stream.
-
- def finish
- return if @inflate.total_in == 0
- @inflate.finish
- end
-
- ##
- # The number of bytes inflated, used to update the Content-Length of
- # the response.
-
- def bytes_inflated
- @inflate.total_out
- end
-
- ##
- # Returns a Gem::Net::ReadAdapter that inflates each read chunk into +dest+.
- #
- # This allows a large response body to be inflated without storing the
- # entire body in memory.
-
- def inflate_adapter(dest)
- if dest.respond_to?(:set_encoding)
- dest.set_encoding(Encoding::ASCII_8BIT)
- elsif dest.respond_to?(:force_encoding)
- dest.force_encoding(Encoding::ASCII_8BIT)
- end
- block = proc do |compressed_chunk|
- @inflate.inflate(compressed_chunk) do |chunk|
- compressed_chunk.clear
- dest << chunk
- end
- end
-
- Gem::Net::ReadAdapter.new(block)
- end
-
- ##
- # Reads +clen+ bytes from the socket, inflates them, then writes them to
- # +dest+. +ignore_eof+ is passed down to Gem::Net::BufferedIO#read
- #
- # Unlike Gem::Net::BufferedIO#read, this method returns more than +clen+ bytes.
- # At this time there is no way for a user of Gem::Net::HTTPResponse to read a
- # specific number of bytes from the HTTP response body, so this internal
- # API does not return the same number of bytes as were requested.
- #
- # See https://bugs.ruby-lang.org/issues/6492 for further discussion.
-
- def read clen, dest, ignore_eof = false
- temp_dest = inflate_adapter(dest)
-
- @socket.read clen, temp_dest, ignore_eof
- end
-
- ##
- # Reads the rest of the socket, inflates it, then writes it to +dest+.
-
- def read_all dest
- temp_dest = inflate_adapter(dest)
-
- @socket.read_all temp_dest
- end
-
- end
-
-end
-
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/responses.rb b/lib/rubygems/vendor/net-http/lib/net/http/responses.rb
deleted file mode 100644
index 0f26ae6c26..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/responses.rb
+++ /dev/null
@@ -1,1174 +0,0 @@
-# frozen_string_literal: true
-#--
-# https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
-
-module Gem::Net
-
- class HTTPUnknownResponse < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPError #
- end
-
- # Parent class for informational (1xx) HTTP response classes.
- #
- # An informational response indicates that the request was received and understood.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.1xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#1xx_informational_response].
- #
- class HTTPInformation < HTTPResponse
- HAS_BODY = false
- EXCEPTION_TYPE = HTTPError #
- end
-
- # Parent class for success (2xx) HTTP response classes.
- #
- # A success response indicates the action requested by the client
- # was received, understood, and accepted.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.2xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success].
- #
- class HTTPSuccess < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPError #
- end
-
- # Parent class for redirection (3xx) HTTP response classes.
- #
- # A redirection response indicates the client must take additional action
- # to complete the request.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.3xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_redirection].
- #
- class HTTPRedirection < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPRetriableError #
- end
-
- # Parent class for client error (4xx) HTTP response classes.
- #
- # A client error response indicates that the client may have caused an error.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.4xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_client_errors].
- #
- class HTTPClientError < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPClientException #
- end
-
- # Parent class for server error (5xx) HTTP response classes.
- #
- # A server error response indicates that the server failed to fulfill a request.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.5xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors].
- #
- class HTTPServerError < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPFatalError #
- end
-
- # Response class for +Continue+ responses (status code 100).
- #
- # A +Continue+ response indicates that the server has received the request headers.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/100].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-100-continue].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#100].
- #
- class HTTPContinue < HTTPInformation
- HAS_BODY = false
- end
-
- # Response class for <tt>Switching Protocol</tt> responses (status code 101).
- #
- # The <tt>Switching Protocol<tt> response indicates that the server has received
- # a request to switch protocols, and has agreed to do so.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/101].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-101-switching-protocols].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#101].
- #
- class HTTPSwitchProtocol < HTTPInformation
- HAS_BODY = false
- end
-
- # Response class for +Processing+ responses (status code 102).
- #
- # The +Processing+ response indicates that the server has received
- # and is processing the request, but no response is available yet.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 2518}[https://www.rfc-editor.org/rfc/rfc2518#section-10.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#102].
- #
- class HTTPProcessing < HTTPInformation
- HAS_BODY = false
- end
-
- # Response class for <tt>Early Hints</tt> responses (status code 103).
- #
- # The <tt>Early Hints</tt> indicates that the server has received
- # and is processing the request, and contains certain headers;
- # the final response is not available yet.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103].
- # - {RFC 8297}[https://www.rfc-editor.org/rfc/rfc8297.html#section-2].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#103].
- #
- class HTTPEarlyHints < HTTPInformation
- HAS_BODY = false
- end
-
- # Response class for +OK+ responses (status code 200).
- #
- # The +OK+ response indicates that the server has received
- # a request and has responded successfully.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-200-ok].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#200].
- #
- class HTTPOK < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for +Created+ responses (status code 201).
- #
- # The +Created+ response indicates that the server has received
- # and has fulfilled a request to create a new resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-201-created].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#201].
- #
- class HTTPCreated < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for +Accepted+ responses (status code 202).
- #
- # The +Accepted+ response indicates that the server has received
- # and is processing a request, but the processing has not yet been completed.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-202-accepted].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#202].
- #
- class HTTPAccepted < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>Non-Authoritative Information</tt> responses (status code 203).
- #
- # The <tt>Non-Authoritative Information</tt> response indicates that the server
- # is a transforming proxy (such as a Web accelerator)
- # that received a 200 OK response from its origin,
- # and is returning a modified version of the origin's response.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/203].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-203-non-authoritative-infor].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#203].
- #
- class HTTPNonAuthoritativeInformation < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>No Content</tt> responses (status code 204).
- #
- # The <tt>No Content</tt> response indicates that the server
- # successfully processed the request, and is not returning any content.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-204-no-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#204].
- #
- class HTTPNoContent < HTTPSuccess
- HAS_BODY = false
- end
-
- # Response class for <tt>Reset Content</tt> responses (status code 205).
- #
- # The <tt>Reset Content</tt> response indicates that the server
- # successfully processed the request,
- # asks that the client reset its document view, and is not returning any content.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/205].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-205-reset-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#205].
- #
- class HTTPResetContent < HTTPSuccess
- HAS_BODY = false
- end
-
- # Response class for <tt>Partial Content</tt> responses (status code 206).
- #
- # The <tt>Partial Content</tt> response indicates that the server is delivering
- # only part of the resource (byte serving)
- # due to a Range header in the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-206-partial-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#206].
- #
- class HTTPPartialContent < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>Multi-Status (WebDAV)</tt> responses (status code 207).
- #
- # The <tt>Multi-Status (WebDAV)</tt> response indicates that the server
- # has received the request,
- # and that the message body can contain a number of separate response codes.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 4818}[https://www.rfc-editor.org/rfc/rfc4918#section-11.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#207].
- #
- class HTTPMultiStatus < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>Already Reported (WebDAV)</tt> responses (status code 208).
- #
- # The <tt>Already Reported (WebDAV)</tt> response indicates that the server
- # has received the request,
- # and that the members of a DAV binding have already been enumerated
- # in a preceding part of the (multi-status) response,
- # and are not being included again.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 5842}[https://www.rfc-editor.org/rfc/rfc5842.html#section-7.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#208].
- #
- class HTTPAlreadyReported < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>IM Used</tt> responses (status code 226).
- #
- # The <tt>IM Used</tt> response indicates that the server has fulfilled a request
- # for the resource, and the response is a representation of the result
- # of one or more instance-manipulations applied to the current instance.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 3229}[https://www.rfc-editor.org/rfc/rfc3229.html#section-10.4.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#226].
- #
- class HTTPIMUsed < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>Multiple Choices</tt> responses (status code 300).
- #
- # The <tt>Multiple Choices</tt> response indicates that the server
- # offers multiple options for the resource from which the client may choose.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/300].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-300-multiple-choices].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#300].
- #
- class HTTPMultipleChoices < HTTPRedirection
- HAS_BODY = true
- end
- HTTPMultipleChoice = HTTPMultipleChoices
-
- # Response class for <tt>Moved Permanently</tt> responses (status code 301).
- #
- # The <tt>Moved Permanently</tt> response indicates that links or records
- # returning this response should be updated to use the given URL.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/301].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-301-moved-permanently].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#301].
- #
- class HTTPMovedPermanently < HTTPRedirection
- HAS_BODY = true
- end
-
- # Response class for <tt>Found</tt> responses (status code 302).
- #
- # The <tt>Found</tt> response indicates that the client
- # should look at (browse to) another URL.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-302-found].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#302].
- #
- class HTTPFound < HTTPRedirection
- HAS_BODY = true
- end
- HTTPMovedTemporarily = HTTPFound
-
- # Response class for <tt>See Other</tt> responses (status code 303).
- #
- # The response to the request can be found under another Gem::URI using the GET method.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/303].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-303-see-other].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#303].
- #
- class HTTPSeeOther < HTTPRedirection
- HAS_BODY = true
- end
-
- # Response class for <tt>Not Modified</tt> responses (status code 304).
- #
- # Indicates that the resource has not been modified since the version
- # specified by the request headers.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-304-not-modified].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#304].
- #
- class HTTPNotModified < HTTPRedirection
- HAS_BODY = false
- end
-
- # Response class for <tt>Use Proxy</tt> responses (status code 305).
- #
- # The requested resource is available only through a proxy,
- # whose address is provided in the response.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-305-use-proxy].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#305].
- #
- class HTTPUseProxy < HTTPRedirection
- HAS_BODY = false
- end
-
- # Response class for <tt>Temporary Redirect</tt> responses (status code 307).
- #
- # The request should be repeated with another Gem::URI;
- # however, future requests should still use the original Gem::URI.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-307-temporary-redirect].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#307].
- #
- class HTTPTemporaryRedirect < HTTPRedirection
- HAS_BODY = true
- end
-
- # Response class for <tt>Permanent Redirect</tt> responses (status code 308).
- #
- # This and all future requests should be directed to the given Gem::URI.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-308-permanent-redirect].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#308].
- #
- class HTTPPermanentRedirect < HTTPRedirection
- HAS_BODY = true
- end
-
- # Response class for <tt>Bad Request</tt> responses (status code 400).
- #
- # The server cannot or will not process the request due to an apparent client error.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-400-bad-request].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#400].
- #
- class HTTPBadRequest < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Unauthorized</tt> responses (status code 401).
- #
- # Authentication is required, but either was not provided or failed.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-401-unauthorized].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#401].
- #
- class HTTPUnauthorized < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Payment Required</tt> responses (status code 402).
- #
- # Reserved for future use.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/402].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-402-payment-required].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#402].
- #
- class HTTPPaymentRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Forbidden</tt> responses (status code 403).
- #
- # The request contained valid data and was understood by the server,
- # but the server is refusing action.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-403-forbidden].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#403].
- #
- class HTTPForbidden < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Not Found</tt> responses (status code 404).
- #
- # The requested resource could not be found but may be available in the future.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-404-not-found].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#404].
- #
- class HTTPNotFound < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Method Not Allowed</tt> responses (status code 405).
- #
- # The request method is not supported for the requested resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-405-method-not-allowed].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#405].
- #
- class HTTPMethodNotAllowed < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Not Acceptable</tt> responses (status code 406).
- #
- # The requested resource is capable of generating only content
- # that not acceptable according to the Accept headers sent in the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/406].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-406-not-acceptable].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#406].
- #
- class HTTPNotAcceptable < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Proxy Authentication Required</tt> responses (status code 407).
- #
- # The client must first authenticate itself with the proxy.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/407].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-407-proxy-authentication-re].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#407].
- #
- class HTTPProxyAuthenticationRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Request Gem::Timeout</tt> responses (status code 408).
- #
- # The server timed out waiting for the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-408-request-timeout].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#408].
- #
- class HTTPRequestTimeout < HTTPClientError
- HAS_BODY = true
- end
- HTTPRequestTimeOut = HTTPRequestTimeout
-
- # Response class for <tt>Conflict</tt> responses (status code 409).
- #
- # The request could not be processed because of conflict in the current state of the resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-409-conflict].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#409].
- #
- class HTTPConflict < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Gone</tt> responses (status code 410).
- #
- # The resource requested was previously in use but is no longer available
- # and will not be available again.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/410].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-410-gone].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#410].
- #
- class HTTPGone < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Length Required</tt> responses (status code 411).
- #
- # The request did not specify the length of its content,
- # which is required by the requested resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/411].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-411-length-required].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#411].
- #
- class HTTPLengthRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Precondition Failed</tt> responses (status code 412).
- #
- # The server does not meet one of the preconditions
- # specified in the request headers.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/412].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-412-precondition-failed].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#412].
- #
- class HTTPPreconditionFailed < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Payload Too Large</tt> responses (status code 413).
- #
- # The request is larger than the server is willing or able to process.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/413].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-413-content-too-large].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#413].
- #
- class HTTPPayloadTooLarge < HTTPClientError
- HAS_BODY = true
- end
- HTTPRequestEntityTooLarge = HTTPPayloadTooLarge
-
- # Response class for <tt>Gem::URI Too Long</tt> responses (status code 414).
- #
- # The Gem::URI provided was too long for the server to process.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/414].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-414-uri-too-long].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#414].
- #
- class HTTPURITooLong < HTTPClientError
- HAS_BODY = true
- end
- HTTPRequestURITooLong = HTTPURITooLong
- HTTPRequestURITooLarge = HTTPRequestURITooLong
-
- # Response class for <tt>Unsupported Media Type</tt> responses (status code 415).
- #
- # The request entity has a media type which the server or resource does not support.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/415].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-415-unsupported-media-type].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#415].
- #
- class HTTPUnsupportedMediaType < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Range Not Satisfiable</tt> responses (status code 416).
- #
- # The request entity has a media type which the server or resource does not support.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-416-range-not-satisfiable].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#416].
- #
- class HTTPRangeNotSatisfiable < HTTPClientError
- HAS_BODY = true
- end
- HTTPRequestedRangeNotSatisfiable = HTTPRangeNotSatisfiable
-
- # Response class for <tt>Expectation Failed</tt> responses (status code 417).
- #
- # The server cannot meet the requirements of the Expect request-header field.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/417].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-417-expectation-failed].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#417].
- #
- class HTTPExpectationFailed < HTTPClientError
- HAS_BODY = true
- end
-
- # 418 I'm a teapot - RFC 2324; a joke RFC
- # See https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#418.
-
- # 420 Enhance Your Calm - Twitter
-
- # Response class for <tt>Misdirected Request</tt> responses (status code 421).
- #
- # The request was directed at a server that is not able to produce a response.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-421-misdirected-request].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#421].
- #
- class HTTPMisdirectedRequest < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Unprocessable Entity</tt> responses (status code 422).
- #
- # The request was well-formed but had semantic errors.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-422-unprocessable-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422].
- #
- class HTTPUnprocessableEntity < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Locked (WebDAV)</tt> responses (status code 423).
- #
- # The requested resource is locked.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 4918}[https://www.rfc-editor.org/rfc/rfc4918#section-11.3].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#423].
- #
- class HTTPLocked < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Failed Dependency (WebDAV)</tt> responses (status code 424).
- #
- # The request failed because it depended on another request and that request failed.
- # See {424 Failed Dependency (WebDAV)}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 4918}[https://www.rfc-editor.org/rfc/rfc4918#section-11.4].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
- #
- class HTTPFailedDependency < HTTPClientError
- HAS_BODY = true
- end
-
- # 425 Too Early
- # https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#425.
-
- # Response class for <tt>Upgrade Required</tt> responses (status code 426).
- #
- # The client should switch to the protocol given in the Upgrade header field.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/426].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-426-upgrade-required].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#426].
- #
- class HTTPUpgradeRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Precondition Required</tt> responses (status code 428).
- #
- # The origin server requires the request to be conditional.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/428].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-3].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#428].
- #
- class HTTPPreconditionRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Too Many Requests</tt> responses (status code 429).
- #
- # The user has sent too many requests in a given amount of time.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-4].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#429].
- #
- class HTTPTooManyRequests < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Request Header Fields Too Large</tt> responses (status code 431).
- #
- # An individual header field is too large,
- # or all the header fields collectively, are too large.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/431].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-5].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#431].
- #
- class HTTPRequestHeaderFieldsTooLarge < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Unavailable For Legal Reasons</tt> responses (status code 451).
- #
- # A server operator has received a legal demand to deny access to a resource or to a set of resources
- # that includes the requested resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/451].
- # - {RFC 7725}[https://www.rfc-editor.org/rfc/rfc7725.html#section-3].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#451].
- #
- class HTTPUnavailableForLegalReasons < HTTPClientError
- HAS_BODY = true
- end
- # 444 No Response - Nginx
- # 449 Retry With - Microsoft
- # 450 Blocked by Windows Parental Controls - Microsoft
- # 499 Client Closed Request - Nginx
-
- # Response class for <tt>Internal Server Error</tt> responses (status code 500).
- #
- # An unexpected condition was encountered and no more specific message is suitable.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-500-internal-server-error].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#500].
- #
- class HTTPInternalServerError < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Not Implemented</tt> responses (status code 501).
- #
- # The server either does not recognize the request method,
- # or it lacks the ability to fulfil the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-501-not-implemented].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#501].
- #
- class HTTPNotImplemented < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Bad Gateway</tt> responses (status code 502).
- #
- # The server was acting as a gateway or proxy
- # and received an invalid response from the upstream server.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-502-bad-gateway].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#502].
- #
- class HTTPBadGateway < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Service Unavailable</tt> responses (status code 503).
- #
- # The server cannot handle the request
- # (because it is overloaded or down for maintenance).
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-503-service-unavailable].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#503].
- #
- class HTTPServiceUnavailable < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Gateway Gem::Timeout</tt> responses (status code 504).
- #
- # The server was acting as a gateway or proxy
- # and did not receive a timely response from the upstream server.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-504-gateway-timeout].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#504].
- #
- class HTTPGatewayTimeout < HTTPServerError
- HAS_BODY = true
- end
- HTTPGatewayTimeOut = HTTPGatewayTimeout
-
- # Response class for <tt>HTTP Version Not Supported</tt> responses (status code 505).
- #
- # The server does not support the HTTP version used in the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/505].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-505-http-version-not-suppor].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#505].
- #
- class HTTPVersionNotSupported < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Variant Also Negotiates</tt> responses (status code 506).
- #
- # Transparent content negotiation for the request results in a circular reference.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/506].
- # - {RFC 2295}[https://www.rfc-editor.org/rfc/rfc2295#section-8.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#506].
- #
- class HTTPVariantAlsoNegotiates < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Insufficient Storage (WebDAV)</tt> responses (status code 507).
- #
- # The server is unable to store the representation needed to complete the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/507].
- # - {RFC 4918}[https://www.rfc-editor.org/rfc/rfc4918#section-11.5].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#507].
- #
- class HTTPInsufficientStorage < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Loop Detected (WebDAV)</tt> responses (status code 508).
- #
- # The server detected an infinite loop while processing the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/508].
- # - {RFC 5942}[https://www.rfc-editor.org/rfc/rfc5842.html#section-7.2].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#508].
- #
- class HTTPLoopDetected < HTTPServerError
- HAS_BODY = true
- end
- # 509 Bandwidth Limit Exceeded - Apache bw/limited extension
-
- # Response class for <tt>Not Extended</tt> responses (status code 510).
- #
- # Further extensions to the request are required for the server to fulfill it.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/510].
- # - {RFC 2774}[https://www.rfc-editor.org/rfc/rfc2774.html#section-7].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#510].
- #
- class HTTPNotExtended < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Network Authentication Required</tt> responses (status code 511).
- #
- # The client needs to authenticate to gain network access.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/511].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-6].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#511].
- #
- class HTTPNetworkAuthenticationRequired < HTTPServerError
- HAS_BODY = true
- end
-
-end
-
-class Gem::Net::HTTPResponse
- CODE_CLASS_TO_OBJ = {
- '1' => Gem::Net::HTTPInformation,
- '2' => Gem::Net::HTTPSuccess,
- '3' => Gem::Net::HTTPRedirection,
- '4' => Gem::Net::HTTPClientError,
- '5' => Gem::Net::HTTPServerError
- }
- CODE_TO_OBJ = {
- '100' => Gem::Net::HTTPContinue,
- '101' => Gem::Net::HTTPSwitchProtocol,
- '102' => Gem::Net::HTTPProcessing,
- '103' => Gem::Net::HTTPEarlyHints,
-
- '200' => Gem::Net::HTTPOK,
- '201' => Gem::Net::HTTPCreated,
- '202' => Gem::Net::HTTPAccepted,
- '203' => Gem::Net::HTTPNonAuthoritativeInformation,
- '204' => Gem::Net::HTTPNoContent,
- '205' => Gem::Net::HTTPResetContent,
- '206' => Gem::Net::HTTPPartialContent,
- '207' => Gem::Net::HTTPMultiStatus,
- '208' => Gem::Net::HTTPAlreadyReported,
- '226' => Gem::Net::HTTPIMUsed,
-
- '300' => Gem::Net::HTTPMultipleChoices,
- '301' => Gem::Net::HTTPMovedPermanently,
- '302' => Gem::Net::HTTPFound,
- '303' => Gem::Net::HTTPSeeOther,
- '304' => Gem::Net::HTTPNotModified,
- '305' => Gem::Net::HTTPUseProxy,
- '307' => Gem::Net::HTTPTemporaryRedirect,
- '308' => Gem::Net::HTTPPermanentRedirect,
-
- '400' => Gem::Net::HTTPBadRequest,
- '401' => Gem::Net::HTTPUnauthorized,
- '402' => Gem::Net::HTTPPaymentRequired,
- '403' => Gem::Net::HTTPForbidden,
- '404' => Gem::Net::HTTPNotFound,
- '405' => Gem::Net::HTTPMethodNotAllowed,
- '406' => Gem::Net::HTTPNotAcceptable,
- '407' => Gem::Net::HTTPProxyAuthenticationRequired,
- '408' => Gem::Net::HTTPRequestTimeout,
- '409' => Gem::Net::HTTPConflict,
- '410' => Gem::Net::HTTPGone,
- '411' => Gem::Net::HTTPLengthRequired,
- '412' => Gem::Net::HTTPPreconditionFailed,
- '413' => Gem::Net::HTTPPayloadTooLarge,
- '414' => Gem::Net::HTTPURITooLong,
- '415' => Gem::Net::HTTPUnsupportedMediaType,
- '416' => Gem::Net::HTTPRangeNotSatisfiable,
- '417' => Gem::Net::HTTPExpectationFailed,
- '421' => Gem::Net::HTTPMisdirectedRequest,
- '422' => Gem::Net::HTTPUnprocessableEntity,
- '423' => Gem::Net::HTTPLocked,
- '424' => Gem::Net::HTTPFailedDependency,
- '426' => Gem::Net::HTTPUpgradeRequired,
- '428' => Gem::Net::HTTPPreconditionRequired,
- '429' => Gem::Net::HTTPTooManyRequests,
- '431' => Gem::Net::HTTPRequestHeaderFieldsTooLarge,
- '451' => Gem::Net::HTTPUnavailableForLegalReasons,
-
- '500' => Gem::Net::HTTPInternalServerError,
- '501' => Gem::Net::HTTPNotImplemented,
- '502' => Gem::Net::HTTPBadGateway,
- '503' => Gem::Net::HTTPServiceUnavailable,
- '504' => Gem::Net::HTTPGatewayTimeout,
- '505' => Gem::Net::HTTPVersionNotSupported,
- '506' => Gem::Net::HTTPVariantAlsoNegotiates,
- '507' => Gem::Net::HTTPInsufficientStorage,
- '508' => Gem::Net::HTTPLoopDetected,
- '510' => Gem::Net::HTTPNotExtended,
- '511' => Gem::Net::HTTPNetworkAuthenticationRequired,
- }
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/status.rb b/lib/rubygems/vendor/net-http/lib/net/http/status.rb
deleted file mode 100644
index 9110b108b8..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/status.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../http'
-
-if $0 == __FILE__
- require 'open-uri'
- File.foreach(__FILE__) do |line|
- puts line
- break if line.start_with?('end')
- end
- puts
- puts "Gem::Net::HTTP::STATUS_CODES = {"
- url = "https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv"
- Gem::URI(url).read.each_line do |line|
- code, mes, = line.split(',')
- next if ['(Unused)', 'Unassigned', 'Description'].include?(mes)
- puts " #{code} => '#{mes}',"
- end
- puts "} # :nodoc:"
-end
-
-Gem::Net::HTTP::STATUS_CODES = {
- 100 => 'Continue',
- 101 => 'Switching Protocols',
- 102 => 'Processing',
- 103 => 'Early Hints',
- 200 => 'OK',
- 201 => 'Created',
- 202 => 'Accepted',
- 203 => 'Non-Authoritative Information',
- 204 => 'No Content',
- 205 => 'Reset Content',
- 206 => 'Partial Content',
- 207 => 'Multi-Status',
- 208 => 'Already Reported',
- 226 => 'IM Used',
- 300 => 'Multiple Choices',
- 301 => 'Moved Permanently',
- 302 => 'Found',
- 303 => 'See Other',
- 304 => 'Not Modified',
- 305 => 'Use Proxy',
- 307 => 'Temporary Redirect',
- 308 => 'Permanent Redirect',
- 400 => 'Bad Request',
- 401 => 'Unauthorized',
- 402 => 'Payment Required',
- 403 => 'Forbidden',
- 404 => 'Not Found',
- 405 => 'Method Not Allowed',
- 406 => 'Not Acceptable',
- 407 => 'Proxy Authentication Required',
- 408 => 'Request Timeout',
- 409 => 'Conflict',
- 410 => 'Gone',
- 411 => 'Length Required',
- 412 => 'Precondition Failed',
- 413 => 'Content Too Large',
- 414 => 'URI Too Long',
- 415 => 'Unsupported Media Type',
- 416 => 'Range Not Satisfiable',
- 417 => 'Expectation Failed',
- 421 => 'Misdirected Request',
- 422 => 'Unprocessable Content',
- 423 => 'Locked',
- 424 => 'Failed Dependency',
- 425 => 'Too Early',
- 426 => 'Upgrade Required',
- 428 => 'Precondition Required',
- 429 => 'Too Many Requests',
- 431 => 'Request Header Fields Too Large',
- 451 => 'Unavailable For Legal Reasons',
- 500 => 'Internal Server Error',
- 501 => 'Not Implemented',
- 502 => 'Bad Gateway',
- 503 => 'Service Unavailable',
- 504 => 'Gateway Timeout',
- 505 => 'HTTP Version Not Supported',
- 506 => 'Variant Also Negotiates',
- 507 => 'Insufficient Storage',
- 508 => 'Loop Detected',
- 510 => 'Not Extended (OBSOLETED)',
- 511 => 'Network Authentication Required',
-} # :nodoc:
diff --git a/lib/rubygems/vendor/net-http/lib/net/https.rb b/lib/rubygems/vendor/net-http/lib/net/https.rb
deleted file mode 100644
index f104c85c81..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/https.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-=begin
-
-= net/https -- SSL/TLS enhancement for Gem::Net::HTTP.
-
- This file has been merged with net/http. There is no longer any need to
- require_relative 'https' to use HTTPS.
-
- See Gem::Net::HTTP for details on how to make HTTPS connections.
-
-== Info
- 'OpenSSL for Ruby 2' project
- Copyright (C) 2001 GOTOU Yuuzou <gotoyuzo@notwork.org>
- All rights reserved.
-
-== Licence
- This program is licensed under the same licence as Ruby.
- (See the file 'LICENCE'.)
-
-=end
-
-require_relative 'http'
-require 'openssl'
diff --git a/lib/rubygems/vendor/net-protocol/.document b/lib/rubygems/vendor/net-protocol/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/net-protocol/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/net-protocol/lib/net/protocol.rb b/lib/rubygems/vendor/net-protocol/lib/net/protocol.rb
deleted file mode 100644
index 53d34d8d98..0000000000
--- a/lib/rubygems/vendor/net-protocol/lib/net/protocol.rb
+++ /dev/null
@@ -1,544 +0,0 @@
-# frozen_string_literal: true
-#
-# = net/protocol.rb
-#
-#--
-# Copyright (c) 1999-2004 Yukihiro Matsumoto
-# Copyright (c) 1999-2004 Minero Aoki
-#
-# written and maintained by Minero Aoki <aamine@loveruby.net>
-#
-# This program is free software. You can re-distribute and/or
-# modify this program under the same terms as Ruby itself,
-# Ruby Distribute License or GNU General Public License.
-#
-# $Id$
-#++
-#
-# WARNING: This file is going to remove.
-# Do not rely on the implementation written in this file.
-#
-
-require 'socket'
-require_relative '../../../timeout/lib/timeout'
-require 'io/wait'
-
-module Gem::Net # :nodoc:
-
- class Protocol #:nodoc: internal use only
- VERSION = "0.2.2"
-
- private
- def Protocol.protocol_param(name, val)
- module_eval(<<-End, __FILE__, __LINE__ + 1)
- def #{name}
- #{val}
- end
- End
- end
-
- def ssl_socket_connect(s, timeout)
- if timeout
- while true
- raise Gem::Net::OpenTimeout if timeout <= 0
- start = Process.clock_gettime Process::CLOCK_MONOTONIC
- # to_io is required because SSLSocket doesn't have wait_readable yet
- case s.connect_nonblock(exception: false)
- when :wait_readable; s.to_io.wait_readable(timeout)
- when :wait_writable; s.to_io.wait_writable(timeout)
- else; break
- end
- timeout -= Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
- end
- else
- s.connect
- end
- end
- end
-
-
- class ProtocolError < StandardError; end
- class ProtoSyntaxError < ProtocolError; end
- class ProtoFatalError < ProtocolError; end
- class ProtoUnknownError < ProtocolError; end
- class ProtoServerError < ProtocolError; end
- class ProtoAuthError < ProtocolError; end
- class ProtoCommandError < ProtocolError; end
- class ProtoRetriableError < ProtocolError; end
- ProtocRetryError = ProtoRetriableError
-
- ##
- # OpenTimeout, a subclass of Gem::Timeout::Error, is raised if a connection cannot
- # be created within the open_timeout.
-
- class OpenTimeout < Gem::Timeout::Error; end
-
- ##
- # ReadTimeout, a subclass of Gem::Timeout::Error, is raised if a chunk of the
- # response cannot be read within the read_timeout.
-
- class ReadTimeout < Gem::Timeout::Error
- def initialize(io = nil)
- @io = io
- end
- attr_reader :io
-
- def message
- msg = super
- if @io
- msg = "#{msg} with #{@io.inspect}"
- end
- msg
- end
- end
-
- ##
- # WriteTimeout, a subclass of Gem::Timeout::Error, is raised if a chunk of the
- # response cannot be written within the write_timeout. Not raised on Windows.
-
- class WriteTimeout < Gem::Timeout::Error
- def initialize(io = nil)
- @io = io
- end
- attr_reader :io
-
- def message
- msg = super
- if @io
- msg = "#{msg} with #{@io.inspect}"
- end
- msg
- end
- end
-
-
- class BufferedIO #:nodoc: internal use only
- def initialize(io, read_timeout: 60, write_timeout: 60, continue_timeout: nil, debug_output: nil)
- @io = io
- @read_timeout = read_timeout
- @write_timeout = write_timeout
- @continue_timeout = continue_timeout
- @debug_output = debug_output
- @rbuf = ''.b
- @rbuf_empty = true
- @rbuf_offset = 0
- end
-
- attr_reader :io
- attr_accessor :read_timeout
- attr_accessor :write_timeout
- attr_accessor :continue_timeout
- attr_accessor :debug_output
-
- def inspect
- "#<#{self.class} io=#{@io}>"
- end
-
- def eof?
- @io.eof?
- end
-
- def closed?
- @io.closed?
- end
-
- def close
- @io.close
- end
-
- #
- # Read
- #
-
- public
-
- def read(len, dest = ''.b, ignore_eof = false)
- LOG "reading #{len} bytes..."
- read_bytes = 0
- begin
- while read_bytes + rbuf_size < len
- if s = rbuf_consume_all
- read_bytes += s.bytesize
- dest << s
- end
- rbuf_fill
- end
- s = rbuf_consume(len - read_bytes)
- read_bytes += s.bytesize
- dest << s
- rescue EOFError
- raise unless ignore_eof
- end
- LOG "read #{read_bytes} bytes"
- dest
- end
-
- def read_all(dest = ''.b)
- LOG 'reading all...'
- read_bytes = 0
- begin
- while true
- if s = rbuf_consume_all
- read_bytes += s.bytesize
- dest << s
- end
- rbuf_fill
- end
- rescue EOFError
- ;
- end
- LOG "read #{read_bytes} bytes"
- dest
- end
-
- def readuntil(terminator, ignore_eof = false)
- offset = @rbuf_offset
- begin
- until idx = @rbuf.index(terminator, offset)
- offset = @rbuf.bytesize
- rbuf_fill
- end
- return rbuf_consume(idx + terminator.bytesize - @rbuf_offset)
- rescue EOFError
- raise unless ignore_eof
- return rbuf_consume
- end
- end
-
- def readline
- readuntil("\n").chop
- end
-
- private
-
- BUFSIZE = 1024 * 16
-
- def rbuf_fill
- tmp = @rbuf_empty ? @rbuf : nil
- case rv = @io.read_nonblock(BUFSIZE, tmp, exception: false)
- when String
- @rbuf_empty = false
- if rv.equal?(tmp)
- @rbuf_offset = 0
- else
- @rbuf << rv
- rv.clear
- end
- return
- when :wait_readable
- (io = @io.to_io).wait_readable(@read_timeout) or raise Gem::Net::ReadTimeout.new(io)
- # continue looping
- when :wait_writable
- # OpenSSL::Buffering#read_nonblock may fail with IO::WaitWritable.
- # http://www.openssl.org/support/faq.html#PROG10
- (io = @io.to_io).wait_writable(@read_timeout) or raise Gem::Net::ReadTimeout.new(io)
- # continue looping
- when nil
- raise EOFError, 'end of file reached'
- end while true
- end
-
- def rbuf_flush
- if @rbuf_empty
- @rbuf.clear
- @rbuf_offset = 0
- end
- nil
- end
-
- def rbuf_size
- @rbuf.bytesize - @rbuf_offset
- end
-
- def rbuf_consume_all
- rbuf_consume if rbuf_size > 0
- end
-
- def rbuf_consume(len = nil)
- if @rbuf_offset == 0 && (len.nil? || len == @rbuf.bytesize)
- s = @rbuf
- @rbuf = ''.b
- @rbuf_offset = 0
- @rbuf_empty = true
- elsif len.nil?
- s = @rbuf.byteslice(@rbuf_offset..-1)
- @rbuf = ''.b
- @rbuf_offset = 0
- @rbuf_empty = true
- else
- s = @rbuf.byteslice(@rbuf_offset, len)
- @rbuf_offset += len
- @rbuf_empty = @rbuf_offset == @rbuf.bytesize
- rbuf_flush
- end
-
- @debug_output << %Q[-> #{s.dump}\n] if @debug_output
- s
- end
-
- #
- # Write
- #
-
- public
-
- def write(*strs)
- writing {
- write0(*strs)
- }
- end
-
- alias << write
-
- def writeline(str)
- writing {
- write0 str + "\r\n"
- }
- end
-
- private
-
- def writing
- @written_bytes = 0
- @debug_output << '<- ' if @debug_output
- yield
- @debug_output << "\n" if @debug_output
- bytes = @written_bytes
- @written_bytes = nil
- bytes
- end
-
- def write0(*strs)
- @debug_output << strs.map(&:dump).join if @debug_output
- orig_written_bytes = @written_bytes
- strs.each_with_index do |str, i|
- need_retry = true
- case len = @io.write_nonblock(str, exception: false)
- when Integer
- @written_bytes += len
- len -= str.bytesize
- if len == 0
- if strs.size == i+1
- return @written_bytes - orig_written_bytes
- else
- need_retry = false
- # next string
- end
- elsif len < 0
- str = str.byteslice(len, -len)
- else # len > 0
- need_retry = false
- # next string
- end
- # continue looping
- when :wait_writable
- (io = @io.to_io).wait_writable(@write_timeout) or raise Gem::Net::WriteTimeout.new(io)
- # continue looping
- end while need_retry
- end
- end
-
- #
- # Logging
- #
-
- private
-
- def LOG_off
- @save_debug_out = @debug_output
- @debug_output = nil
- end
-
- def LOG_on
- @debug_output = @save_debug_out
- end
-
- def LOG(msg)
- return unless @debug_output
- @debug_output << msg + "\n"
- end
- end
-
-
- class InternetMessageIO < BufferedIO #:nodoc: internal use only
- def initialize(*, **)
- super
- @wbuf = nil
- end
-
- #
- # Read
- #
-
- def each_message_chunk
- LOG 'reading message...'
- LOG_off()
- read_bytes = 0
- while (line = readuntil("\r\n")) != ".\r\n"
- read_bytes += line.size
- yield line.delete_prefix('.')
- end
- LOG_on()
- LOG "read message (#{read_bytes} bytes)"
- end
-
- # *library private* (cannot handle 'break')
- def each_list_item
- while (str = readuntil("\r\n")) != ".\r\n"
- yield str.chop
- end
- end
-
- def write_message_0(src)
- prev = @written_bytes
- each_crlf_line(src) do |line|
- write0 dot_stuff(line)
- end
- @written_bytes - prev
- end
-
- #
- # Write
- #
-
- def write_message(src)
- LOG "writing message from #{src.class}"
- LOG_off()
- len = writing {
- using_each_crlf_line {
- write_message_0 src
- }
- }
- LOG_on()
- LOG "wrote #{len} bytes"
- len
- end
-
- def write_message_by_block(&block)
- LOG 'writing message from block'
- LOG_off()
- len = writing {
- using_each_crlf_line {
- begin
- block.call(WriteAdapter.new(self.method(:write_message_0)))
- rescue LocalJumpError
- # allow `break' from writer block
- end
- }
- }
- LOG_on()
- LOG "wrote #{len} bytes"
- len
- end
-
- private
-
- def dot_stuff(s)
- s.sub(/\A\./, '..')
- end
-
- def using_each_crlf_line
- @wbuf = ''.b
- yield
- if not @wbuf.empty? # unterminated last line
- write0 dot_stuff(@wbuf.chomp) + "\r\n"
- elsif @written_bytes == 0 # empty src
- write0 "\r\n"
- end
- write0 ".\r\n"
- @wbuf = nil
- end
-
- def each_crlf_line(src)
- buffer_filling(@wbuf, src) do
- while line = @wbuf.slice!(/\A[^\r\n]*(?:\n|\r(?:\n|(?!\z)))/)
- yield line.chomp("\n") + "\r\n"
- end
- end
- end
-
- def buffer_filling(buf, src)
- case src
- when String # for speeding up.
- 0.step(src.size - 1, 1024) do |i|
- buf << src[i, 1024]
- yield
- end
- when File # for speeding up.
- while s = src.read(1024)
- buf << s
- yield
- end
- else # generic reader
- src.each do |str|
- buf << str
- yield if buf.size > 1024
- end
- yield unless buf.empty?
- end
- end
- end
-
-
- #
- # The writer adapter class
- #
- class WriteAdapter
- def initialize(writer)
- @writer = writer
- end
-
- def inspect
- "#<#{self.class} writer=#{@writer.inspect}>"
- end
-
- def write(str)
- @writer.call(str)
- end
-
- alias print write
-
- def <<(str)
- write str
- self
- end
-
- def puts(str = '')
- write str.chomp("\n") + "\n"
- end
-
- def printf(*args)
- write sprintf(*args)
- end
- end
-
-
- class ReadAdapter #:nodoc: internal use only
- def initialize(block)
- @block = block
- end
-
- def inspect
- "#<#{self.class}>"
- end
-
- def <<(str)
- call_block(str, &@block) if @block
- end
-
- private
-
- # This method is needed because @block must be called by yield,
- # not Proc#call. You can see difference when using `break' in
- # the block.
- def call_block(str)
- yield str
- end
- end
-
-
- module NetPrivate #:nodoc: obsolete
- Socket = ::Gem::Net::InternetMessageIO
- end
-
-end # module Gem::Net
diff --git a/lib/rubygems/vendor/optparse/.document b/lib/rubygems/vendor/optparse/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/optparse/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/optparse/lib/optparse.rb b/lib/rubygems/vendor/optparse/lib/optparse.rb
deleted file mode 100644
index 00dc7c8a67..0000000000
--- a/lib/rubygems/vendor/optparse/lib/optparse.rb
+++ /dev/null
@@ -1,2330 +0,0 @@
-# frozen_string_literal: true
-#
-# optparse.rb - command-line option analysis with the Gem::OptionParser class.
-#
-# Author:: Nobu Nakada
-# Documentation:: Nobu Nakada and Gavin Sinclair.
-#
-# See Gem::OptionParser for documentation.
-#
-
-
-#--
-# == Developer Documentation (not for RDoc output)
-#
-# === Class tree
-#
-# - Gem::OptionParser:: front end
-# - Gem::OptionParser::Switch:: each switches
-# - Gem::OptionParser::List:: options list
-# - Gem::OptionParser::ParseError:: errors on parsing
-# - Gem::OptionParser::AmbiguousOption
-# - Gem::OptionParser::NeedlessArgument
-# - Gem::OptionParser::MissingArgument
-# - Gem::OptionParser::InvalidOption
-# - Gem::OptionParser::InvalidArgument
-# - Gem::OptionParser::AmbiguousArgument
-#
-# === Object relationship diagram
-#
-# +--------------+
-# | Gem::OptionParser |<>-----+
-# +--------------+ | +--------+
-# | ,-| Switch |
-# on_head -------->+---------------+ / +--------+
-# accept/reject -->| List |<|>-
-# | |<|>- +----------+
-# on ------------->+---------------+ `-| argument |
-# : : | class |
-# +---------------+ |==========|
-# on_tail -------->| | |pattern |
-# +---------------+ |----------|
-# Gem::OptionParser.accept ->| DefaultList | |converter |
-# reject |(shared between| +----------+
-# | all instances)|
-# +---------------+
-#
-#++
-#
-# == Gem::OptionParser
-#
-# === New to +Gem::OptionParser+?
-#
-# See the {Tutorial}[optparse/tutorial.rdoc].
-#
-# === Introduction
-#
-# Gem::OptionParser is a class for command-line option analysis. It is much more
-# advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented
-# solution.
-#
-# === Features
-#
-# 1. The argument specification and the code to handle it are written in the
-# same place.
-# 2. It can output an option summary; you don't need to maintain this string
-# separately.
-# 3. Optional and mandatory arguments are specified very gracefully.
-# 4. Arguments can be automatically converted to a specified class.
-# 5. Arguments can be restricted to a certain set.
-#
-# All of these features are demonstrated in the examples below. See
-# #make_switch for full documentation.
-#
-# === Minimal example
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# options = {}
-# Gem::OptionParser.new do |parser|
-# parser.banner = "Usage: example.rb [options]"
-#
-# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
-# options[:verbose] = v
-# end
-# end.parse!
-#
-# p options
-# p ARGV
-#
-# === Generating Help
-#
-# Gem::OptionParser can be used to automatically generate help for the commands you
-# write:
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# Options = Struct.new(:name)
-#
-# class Parser
-# def self.parse(options)
-# args = Options.new("world")
-#
-# opt_parser = Gem::OptionParser.new do |parser|
-# parser.banner = "Usage: example.rb [options]"
-#
-# parser.on("-nNAME", "--name=NAME", "Name to say hello to") do |n|
-# args.name = n
-# end
-#
-# parser.on("-h", "--help", "Prints this help") do
-# puts parser
-# exit
-# end
-# end
-#
-# opt_parser.parse!(options)
-# return args
-# end
-# end
-# options = Parser.parse %w[--help]
-#
-# #=>
-# # Usage: example.rb [options]
-# # -n, --name=NAME Name to say hello to
-# # -h, --help Prints this help
-#
-# === Required Arguments
-#
-# For options that require an argument, option specification strings may include an
-# option name in all caps. If an option is used without the required argument,
-# an exception will be raised.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# options = {}
-# Gem::OptionParser.new do |parser|
-# parser.on("-r", "--require LIBRARY",
-# "Require the LIBRARY before executing your script") do |lib|
-# puts "You required #{lib}!"
-# end
-# end.parse!
-#
-# Used:
-#
-# $ ruby optparse-test.rb -r
-# optparse-test.rb:9:in `<main>': missing argument: -r (Gem::OptionParser::MissingArgument)
-# $ ruby optparse-test.rb -r my-library
-# You required my-library!
-#
-# === Type Coercion
-#
-# Gem::OptionParser supports the ability to coerce command line arguments
-# into objects for us.
-#
-# Gem::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 +Gem::URI.parse+ (need to require +optparse/uri+)
-# - Shellwords -- Anything accepted by +Shellwords.shellwords+ (need to require +optparse/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)
-# - Numeric -- Any integer, float, or rational (1, 3.4, 1/3)
-# - DecimalInteger -- Like +Integer+, but no octal format.
-# - OctalInteger -- Like +Integer+, but no decimal format.
-# - DecimalNumeric -- Decimal integer or float.
-# - TrueClass -- Accepts '+, yes, true, -, no, false' and
-# defaults as +true+
-# - FalseClass -- Same as +TrueClass+, but defaults to +false+
-# - Array -- Strings separated by ',' (e.g. 1,2,3)
-# - Regexp -- Regular expressions. Also includes options.
-#
-# We can also add our own coercions, which we will cover below.
-#
-# ==== Using Built-in Conversions
-#
-# As an example, the built-in +Time+ conversion is used. The other built-in
-# conversions behave in the same way.
-# Gem::OptionParser will attempt to parse the argument
-# as a +Time+. If it succeeds, that time will be passed to the
-# handler block. Otherwise, an exception will be raised.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-# require 'rubygems/vendor/optparse/lib/optparse/time'
-# Gem::OptionParser.new do |parser|
-# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
-# p time
-# end
-# end.parse!
-#
-# Used:
-#
-# $ ruby optparse-test.rb -t nonsense
-# ... invalid argument: -t nonsense (Gem::OptionParser::InvalidArgument)
-# $ ruby optparse-test.rb -t 10-11-12
-# 2010-11-12 00:00:00 -0500
-# $ ruby optparse-test.rb -t 9:30
-# 2014-08-13 09:30:00 -0400
-#
-# ==== Creating Custom Conversions
-#
-# The +accept+ method on Gem::OptionParser may be used to create converters.
-# It specifies which conversion block to call whenever a class is specified.
-# The example below uses it to fetch a +User+ object before the +on+ handler receives it.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# User = Struct.new(:id, :name)
-#
-# def find_user id
-# not_found = ->{ raise "No User Found for id #{id}" }
-# [ User.new(1, "Sam"),
-# User.new(2, "Gandalf") ].find(not_found) do |u|
-# u.id == id
-# end
-# end
-#
-# op = Gem::OptionParser.new
-# op.accept(User) do |user_id|
-# find_user user_id.to_i
-# end
-#
-# op.on("--user ID", User) do |user|
-# puts user
-# end
-#
-# op.parse!
-#
-# Used:
-#
-# $ ruby optparse-test.rb --user 1
-# #<struct User id=1, name="Sam">
-# $ ruby optparse-test.rb --user 2
-# #<struct User id=2, name="Gandalf">
-# $ ruby optparse-test.rb --user 3
-# optparse-test.rb:15:in `block in find_user': No User Found for id 3 (RuntimeError)
-#
-# === Store options to a Hash
-#
-# The +into+ option of +order+, +parse+ and so on methods stores command line options into a Hash.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# options = {}
-# Gem::OptionParser.new do |parser|
-# parser.on('-a')
-# parser.on('-b NUM', Integer)
-# parser.on('-v', '--verbose')
-# end.parse!(into: options)
-#
-# p options
-#
-# Used:
-#
-# $ ruby optparse-test.rb -a
-# {:a=>true}
-# $ ruby optparse-test.rb -a -v
-# {:a=>true, :verbose=>true}
-# $ ruby optparse-test.rb -a -b 100
-# {:a=>true, :b=>100}
-#
-# === Complete example
-#
-# The following example is a complete Ruby program. You can run it and see the
-# effect of specifying various options. This is probably the best way to learn
-# the features of +optparse+.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-# require 'rubygems/vendor/optparse/lib/optparse/time'
-# require 'ostruct'
-# require 'pp'
-#
-# class OptparseExample
-# Version = '1.0.0'
-#
-# CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
-# CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
-#
-# class ScriptOptions
-# attr_accessor :library, :inplace, :encoding, :transfer_type,
-# :verbose, :extension, :delay, :time, :record_separator,
-# :list
-#
-# def initialize
-# self.library = []
-# self.inplace = false
-# self.encoding = "utf8"
-# self.transfer_type = :auto
-# self.verbose = false
-# end
-#
-# def define_options(parser)
-# parser.banner = "Usage: example.rb [options]"
-# parser.separator ""
-# parser.separator "Specific options:"
-#
-# # add additional options
-# perform_inplace_option(parser)
-# delay_execution_option(parser)
-# execute_at_time_option(parser)
-# specify_record_separator_option(parser)
-# list_example_option(parser)
-# specify_encoding_option(parser)
-# optional_option_argument_with_keyword_completion_option(parser)
-# boolean_verbose_option(parser)
-#
-# parser.separator ""
-# parser.separator "Common options:"
-# # No argument, shows at tail. This will print an options summary.
-# # Try it and see!
-# parser.on_tail("-h", "--help", "Show this message") do
-# puts parser
-# exit
-# end
-# # Another typical switch to print the version.
-# parser.on_tail("--version", "Show version") do
-# puts Version
-# exit
-# end
-# end
-#
-# def perform_inplace_option(parser)
-# # Specifies an optional option argument
-# parser.on("-i", "--inplace [EXTENSION]",
-# "Edit ARGV files in place",
-# "(make backup if EXTENSION supplied)") do |ext|
-# self.inplace = true
-# self.extension = ext || ''
-# self.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
-# end
-# end
-#
-# def delay_execution_option(parser)
-# # Cast 'delay' argument to a Float.
-# parser.on("--delay N", Float, "Delay N seconds before executing") do |n|
-# self.delay = n
-# end
-# end
-#
-# def execute_at_time_option(parser)
-# # Cast 'time' argument to a Time object.
-# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
-# self.time = time
-# end
-# end
-#
-# def specify_record_separator_option(parser)
-# # Cast to octal integer.
-# parser.on("-F", "--irs [OCTAL]", Gem::OptionParser::OctalInteger,
-# "Specify record separator (default \\0)") do |rs|
-# self.record_separator = rs
-# end
-# end
-#
-# def list_example_option(parser)
-# # List of arguments.
-# parser.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
-# self.list = list
-# end
-# end
-#
-# def specify_encoding_option(parser)
-# # Keyword completion. We are specifying a specific set of arguments (CODES
-# # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
-# # the shortest unambiguous text.
-# code_list = (CODE_ALIASES.keys + CODES).join(', ')
-# parser.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
-# "(#{code_list})") do |encoding|
-# self.encoding = encoding
-# end
-# end
-#
-# def optional_option_argument_with_keyword_completion_option(parser)
-# # Optional '--type' option argument with keyword completion.
-# parser.on("--type [TYPE]", [:text, :binary, :auto],
-# "Select transfer type (text, binary, auto)") do |t|
-# self.transfer_type = t
-# end
-# end
-#
-# def boolean_verbose_option(parser)
-# # Boolean switch.
-# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
-# self.verbose = v
-# end
-# end
-# end
-#
-# #
-# # Return a structure describing the options.
-# #
-# def parse(args)
-# # The options specified on the command line will be collected in
-# # *options*.
-#
-# @options = ScriptOptions.new
-# @args = Gem::OptionParser.new do |parser|
-# @options.define_options(parser)
-# parser.parse!(args)
-# end
-# @options
-# end
-#
-# attr_reader :parser, :options
-# end # class OptparseExample
-#
-# example = OptparseExample.new
-# options = example.parse(ARGV)
-# pp options # example.options
-# pp ARGV
-#
-# === Shell Completion
-#
-# For modern shells (e.g. bash, zsh, etc.), you can use shell
-# completion for command line options.
-#
-# === Further documentation
-#
-# The above examples, along with the accompanying
-# {Tutorial}[optparse/tutorial.rdoc],
-# should be enough to learn how to use this class.
-# If you have any questions, file a ticket at http://bugs.ruby-lang.org.
-#
-class Gem::OptionParser
- Gem::OptionParser::Version = "0.4.0"
-
- # :stopdoc:
- NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
- RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
- OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
- # :startdoc:
-
- #
- # Keyword completion module. This allows partial arguments to be specified
- # and resolved against a list of acceptable values.
- #
- module Completion
- def self.regexp(key, icase)
- Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase)
- end
-
- def self.candidate(key, icase = false, pat = nil, &block)
- pat ||= Completion.regexp(key, icase)
- candidates = []
- block.call do |k, *v|
- (if Regexp === k
- kn = ""
- k === key
- else
- kn = defined?(k.id2name) ? k.id2name : k
- pat === kn
- end) or next
- v << k if v.empty?
- candidates << [k, v, kn]
- end
- candidates
- end
-
- def candidate(key, icase = false, pat = nil)
- Completion.candidate(key, icase, pat, &method(:each))
- end
-
- public
- def complete(key, icase = false, pat = nil)
- candidates = candidate(key, icase, pat, &method(:each)).sort_by {|k, v, kn| kn.size}
- if candidates.size == 1
- canon, sw, * = candidates[0]
- elsif candidates.size > 1
- canon, sw, cn = candidates.shift
- candidates.each do |k, v, kn|
- next if sw == v
- if String === cn and String === kn
- if cn.rindex(kn, 0)
- canon, sw, cn = k, v, kn
- next
- elsif kn.rindex(cn, 0)
- next
- end
- end
- throw :ambiguous, key
- end
- end
- if canon
- block_given? or return key, *sw
- yield(key, *sw)
- end
- end
-
- def convert(opt = nil, val = nil, *)
- val
- end
- end
-
-
- #
- # Map from option/keyword string to object with completion.
- #
- class OptionMap < Hash
- include Completion
- end
-
-
- #
- # Individual switch class. Not important to the user.
- #
- # Defined within Switch are several Switch-derived classes: NoArgument,
- # RequiredArgument, etc.
- #
- class Switch
- attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
-
- #
- # Guesses argument style from +arg+. Returns corresponding
- # Gem::OptionParser::Switch class (OptionalArgument, etc.).
- #
- def self.guess(arg)
- case arg
- when ""
- t = self
- when /\A=?\[/
- t = Switch::OptionalArgument
- when /\A\s+\[/
- t = Switch::PlacedArgument
- else
- t = Switch::RequiredArgument
- end
- self >= t or incompatible_argument_styles(arg, t)
- t
- end
-
- def self.incompatible_argument_styles(arg, t)
- raise(ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}",
- ParseError.filter_backtrace(caller(2)))
- end
-
- def self.pattern
- NilClass
- end
-
- def initialize(pattern = nil, conv = nil,
- short = nil, long = nil, arg = nil,
- desc = ([] if short or long), block = nil, &_block)
- raise if Array === pattern
- block ||= _block
- @pattern, @conv, @short, @long, @arg, @desc, @block =
- pattern, conv, short, long, arg, desc, block
- end
-
- #
- # Parses +arg+ and returns rest of +arg+ and matched portion to the
- # argument pattern. Yields when the pattern doesn't match substring.
- #
- def parse_arg(arg) # :nodoc:
- pattern or return nil, [arg]
- unless m = pattern.match(arg)
- yield(InvalidArgument, arg)
- return arg, []
- end
- if String === m
- m = [s = m]
- else
- m = m.to_a
- s = m[0]
- return nil, m unless String === s
- end
- raise InvalidArgument, arg unless arg.rindex(s, 0)
- return nil, m if s.length == arg.length
- yield(InvalidArgument, arg) # didn't match whole arg
- return arg[s.length..-1], m
- end
- private :parse_arg
-
- #
- # Parses argument, converts and returns +arg+, +block+ and result of
- # conversion. Yields at semi-error condition instead of raising an
- # exception.
- #
- def conv_arg(arg, val = []) # :nodoc:
- if conv
- val = conv.call(*val)
- else
- val = proc {|v| v}.call(*val)
- end
- return arg, block, val
- end
- private :conv_arg
-
- #
- # Produces the summary text. Each line of the summary is yielded to the
- # block (without newline).
- #
- # +sdone+:: Already summarized short style options keyed hash.
- # +ldone+:: Already summarized long style options keyed hash.
- # +width+:: Width of left side (option part). In other words, the right
- # side (description part) starts after +width+ columns.
- # +max+:: Maximum width of left side -> the options are filled within
- # +max+ columns.
- # +indent+:: Prefix string indents all summarized lines.
- #
- def summarize(sdone = {}, ldone = {}, width = 1, max = width - 1, indent = "")
- sopts, lopts = [], [], nil
- @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
- @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
- return if sopts.empty? and lopts.empty? # completely hidden
-
- left = [sopts.join(', ')]
- right = desc.dup
-
- while s = lopts.shift
- l = left[-1].length + s.length
- l += arg.length if left.size == 1 && arg
- l < max or sopts.empty? or left << +''
- left[-1] << (left[-1].empty? ? ' ' * 4 : ', ') << s
- end
-
- if arg
- left[0] << (left[1] ? arg.sub(/\A(\[?)=/, '\1') + ',' : arg)
- end
- mlen = left.collect {|ss| ss.length}.max.to_i
- while mlen > width and l = left.shift
- mlen = left.collect {|ss| ss.length}.max.to_i if l.length == mlen
- if l.length < width and (r = right[0]) and !r.empty?
- l = l.to_s.ljust(width) + ' ' + r
- right.shift
- end
- yield(indent + l)
- end
-
- while begin l = left.shift; r = right.shift; l or r end
- l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
- yield(indent + l)
- end
-
- self
- end
-
- def add_banner(to) # :nodoc:
- unless @short or @long
- s = desc.join
- to << " [" + s + "]..." unless s.empty?
- end
- to
- end
-
- def match_nonswitch?(str) # :nodoc:
- @pattern =~ str unless @short or @long
- end
-
- #
- # Main name of the switch.
- #
- def switch_name
- (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '')
- end
-
- def compsys(sdone, ldone) # :nodoc:
- sopts, lopts = [], []
- @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
- @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
- return if sopts.empty? and lopts.empty? # completely hidden
-
- (sopts+lopts).each do |opt|
- # "(-x -c -r)-l[left justify]"
- if /^--\[no-\](.+)$/ =~ opt
- o = $1
- yield("--#{o}", desc.join(""))
- yield("--no-#{o}", desc.join(""))
- else
- yield("#{opt}", desc.join(""))
- end
- end
- end
-
- def pretty_print_contents(q) # :nodoc:
- if @block
- q.text ":" + @block.source_location.join(":") + ":"
- first = false
- else
- first = true
- end
- [@short, @long].each do |list|
- list.each do |opt|
- if first
- q.text ":"
- first = false
- end
- q.breakable
- q.text opt
- end
- end
- end
-
- def pretty_print(q) # :nodoc:
- q.object_group(self) {pretty_print_contents(q)}
- end
-
- #
- # Switch that takes no arguments.
- #
- class NoArgument < self
-
- #
- # Raises an exception if any arguments given.
- #
- def parse(arg, argv)
- yield(NeedlessArgument, arg) if arg
- conv_arg(arg)
- end
-
- def self.incompatible_argument_styles(*)
- end
-
- def self.pattern
- Object
- end
-
- def pretty_head # :nodoc:
- "NoArgument"
- end
- end
-
- #
- # Switch that takes an argument.
- #
- class RequiredArgument < self
-
- #
- # Raises an exception if argument is not present.
- #
- def parse(arg, argv)
- unless arg
- raise MissingArgument if argv.empty?
- arg = argv.shift
- end
- conv_arg(*parse_arg(arg, &method(:raise)))
- end
-
- def pretty_head # :nodoc:
- "Required"
- end
- end
-
- #
- # Switch that can omit argument.
- #
- class OptionalArgument < self
-
- #
- # Parses argument if given, or uses default value.
- #
- def parse(arg, argv, &error)
- if arg
- conv_arg(*parse_arg(arg, &error))
- else
- conv_arg(arg)
- end
- end
-
- def pretty_head # :nodoc:
- "Optional"
- end
- end
-
- #
- # Switch that takes an argument, which does not begin with '-' or is '-'.
- #
- class PlacedArgument < self
-
- #
- # Returns nil if argument is not present or begins with '-' and is not '-'.
- #
- def parse(arg, argv, &error)
- if !(val = arg) and (argv.empty? or /\A-./ =~ (val = argv[0]))
- return nil, block, nil
- end
- opt = (val = parse_arg(val, &error))[1]
- val = conv_arg(*val)
- if opt and !arg
- argv.shift
- else
- val[0] = nil
- end
- val
- end
-
- def pretty_head # :nodoc:
- "Placed"
- end
- end
- end
-
- #
- # Simple option list providing mapping from short and/or long option
- # string to Gem::OptionParser::Switch and mapping from acceptable argument to
- # matching pattern and converter pair. Also provides summary feature.
- #
- class List
- # Map from acceptable argument types to pattern and converter pairs.
- attr_reader :atype
-
- # Map from short style option switches to actual switch objects.
- attr_reader :short
-
- # Map from long style option switches to actual switch objects.
- attr_reader :long
-
- # List of all switches and summary string.
- attr_reader :list
-
- #
- # Just initializes all instance variables.
- #
- def initialize
- @atype = {}
- @short = OptionMap.new
- @long = OptionMap.new
- @list = []
- end
-
- def pretty_print(q) # :nodoc:
- q.group(1, "(", ")") do
- @list.each do |sw|
- next unless Switch === sw
- q.group(1, "(" + sw.pretty_head, ")") do
- sw.pretty_print_contents(q)
- end
- end
- end
- end
-
- #
- # See Gem::OptionParser.accept.
- #
- def accept(t, pat = /.*/m, &block)
- if pat
- pat.respond_to?(:match) or
- raise TypeError, "has no `match'", ParseError.filter_backtrace(caller(2))
- else
- pat = t if t.respond_to?(:match)
- end
- unless block
- block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
- end
- @atype[t] = [pat, block]
- end
-
- #
- # See Gem::OptionParser.reject.
- #
- def reject(t)
- @atype.delete(t)
- end
-
- #
- # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+.
- #
- # +sw+:: Gem::OptionParser::Switch instance to be added.
- # +sopts+:: Short style option list.
- # +lopts+:: Long style option list.
- # +nlopts+:: Negated long style options list.
- #
- def update(sw, sopts, lopts, nsw = nil, nlopts = nil) # :nodoc:
- sopts.each {|o| @short[o] = sw} if sopts
- lopts.each {|o| @long[o] = sw} if lopts
- nlopts.each {|o| @long[o] = nsw} if nsw and nlopts
- used = @short.invert.update(@long.invert)
- @list.delete_if {|o| Switch === o and !used[o]}
- end
- private :update
-
- #
- # Inserts +switch+ at the head of the list, and associates short, long
- # and negated long options. Arguments are:
- #
- # +switch+:: Gem::OptionParser::Switch instance to be inserted.
- # +short_opts+:: List of short style options.
- # +long_opts+:: List of long style options.
- # +nolong_opts+:: List of long style options with "no-" prefix.
- #
- # prepend(switch, short_opts, long_opts, nolong_opts)
- #
- def prepend(*args)
- update(*args)
- @list.unshift(args[0])
- end
-
- #
- # Appends +switch+ at the tail of the list, and associates short, long
- # and negated long options. Arguments are:
- #
- # +switch+:: Gem::OptionParser::Switch instance to be inserted.
- # +short_opts+:: List of short style options.
- # +long_opts+:: List of long style options.
- # +nolong_opts+:: List of long style options with "no-" prefix.
- #
- # append(switch, short_opts, long_opts, nolong_opts)
- #
- def append(*args)
- update(*args)
- @list.push(args[0])
- end
-
- #
- # Searches +key+ in +id+ list. The result is returned or yielded if a
- # block is given. If it isn't found, nil is returned.
- #
- def search(id, key)
- if list = __send__(id)
- val = list.fetch(key) {return nil}
- block_given? ? yield(val) : val
- end
- end
-
- #
- # Searches list +id+ for +opt+ and the optional patterns for completion
- # +pat+. If +icase+ is true, the search is case insensitive. The result
- # is returned or yielded if a block is given. If it isn't found, nil is
- # returned.
- #
- def complete(id, opt, icase = false, *pat, &block)
- __send__(id).complete(opt, icase, *pat, &block)
- end
-
- def get_candidates(id)
- yield __send__(id).keys
- end
-
- #
- # Iterates over each option, passing the option to the +block+.
- #
- def each_option(&block)
- list.each(&block)
- end
-
- #
- # Creates the summary table, passing each line to the +block+ (without
- # newline). The arguments +args+ are passed along to the summarize
- # method which is called on every option.
- #
- def summarize(*args, &block)
- sum = []
- list.reverse_each do |opt|
- if opt.respond_to?(:summarize) # perhaps Gem::OptionParser::Switch
- s = []
- opt.summarize(*args) {|l| s << l}
- sum.concat(s.reverse)
- elsif !opt or opt.empty?
- sum << ""
- elsif opt.respond_to?(:each_line)
- sum.concat([*opt.each_line].reverse)
- else
- sum.concat([*opt.each].reverse)
- end
- end
- sum.reverse_each(&block)
- end
-
- def add_banner(to) # :nodoc:
- list.each do |opt|
- if opt.respond_to?(:add_banner)
- opt.add_banner(to)
- end
- end
- to
- end
-
- def compsys(*args, &block) # :nodoc:
- list.each do |opt|
- if opt.respond_to?(:compsys)
- opt.compsys(*args, &block)
- end
- end
- end
- end
-
- #
- # Hash with completion search feature. See Gem::OptionParser::Completion.
- #
- class CompletingHash < Hash
- include Completion
-
- #
- # Completion for hash key.
- #
- def match(key)
- *values = fetch(key) {
- raise AmbiguousArgument, catch(:ambiguous) {return complete(key)}
- }
- return key, *values
- end
- end
-
- # :stopdoc:
-
- #
- # Enumeration of acceptable argument styles. Possible values are:
- #
- # NO_ARGUMENT:: The switch takes no arguments. (:NONE)
- # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED)
- # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL)
- #
- # Use like --switch=argument (long style) or -Xargument (short style). For
- # short style, only portion matched to argument pattern is treated as
- # argument.
- #
- ArgumentStyle = {}
- NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument}
- RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument}
- OptionalArgument.each {|el| ArgumentStyle[el] = Switch::OptionalArgument}
- ArgumentStyle.freeze
-
- #
- # Switches common used such as '--', and also provides default
- # argument classes
- #
- DefaultList = List.new
- DefaultList.short['-'] = Switch::NoArgument.new {}
- DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
-
-
- COMPSYS_HEADER = <<'XXX' # :nodoc:
-
-typeset -A opt_args
-local context state line
-
-_arguments -s -S \
-XXX
-
- def compsys(to, name = File.basename($0)) # :nodoc:
- to << "#compdef #{name}\n"
- to << COMPSYS_HEADER
- visit(:compsys, {}, {}) {|o, d|
- to << %Q[ "#{o}[#{d.gsub(/[\"\[\]]/, '\\\\\&')}]" \\\n]
- }
- to << " '*:file:_files' && return 0\n"
- end
-
- #
- # Default options for ARGV, which never appear in option summary.
- #
- Officious = {}
-
- #
- # --help
- # Shows option summary.
- #
- Officious['help'] = proc do |parser|
- Switch::NoArgument.new do |arg|
- puts parser.help
- exit
- end
- end
-
- #
- # --*-completion-bash=WORD
- # Shows candidates for command line completion.
- #
- Officious['*-completion-bash'] = proc do |parser|
- Switch::RequiredArgument.new do |arg|
- puts parser.candidate(arg)
- exit
- end
- end
-
- #
- # --*-completion-zsh[=NAME:FILE]
- # Creates zsh completion file.
- #
- Officious['*-completion-zsh'] = proc do |parser|
- Switch::OptionalArgument.new do |arg|
- parser.compsys(STDOUT, arg)
- exit
- end
- end
-
- #
- # --version
- # Shows version string if Version is defined.
- #
- Officious['version'] = proc do |parser|
- Switch::OptionalArgument.new do |pkg|
- if pkg
- begin
- require_relative 'optparse/version'
- rescue LoadError
- else
- show_version(*pkg.split(/,/)) or
- abort("#{parser.program_name}: no version found in package #{pkg}")
- exit
- end
- end
- v = parser.ver or abort("#{parser.program_name}: version unknown")
- puts v
- exit
- end
- end
-
- # :startdoc:
-
- #
- # Class methods
- #
-
- #
- # Initializes a new instance and evaluates the optional block in context
- # of the instance. Arguments +args+ are passed to #new, see there for
- # description of parameters.
- #
- # This method is *deprecated*, its behavior corresponds to the older #new
- # method.
- #
- def self.with(*args, &block)
- opts = new(*args)
- opts.instance_eval(&block)
- opts
- end
-
- #
- # Returns an incremented value of +default+ according to +arg+.
- #
- def self.inc(arg, default = nil)
- case arg
- when Integer
- arg.nonzero?
- when nil
- default.to_i + 1
- end
- end
- def inc(*args)
- self.class.inc(*args)
- end
-
- #
- # Initializes the instance and yields itself if called with a block.
- #
- # +banner+:: Banner message.
- # +width+:: Summary width.
- # +indent+:: Summary indent.
- #
- def initialize(banner = nil, width = 32, indent = ' ' * 4)
- @stack = [DefaultList, List.new, List.new]
- @program_name = nil
- @banner = banner
- @summary_width = width
- @summary_indent = indent
- @default_argv = ARGV
- @require_exact = false
- @raise_unknown = true
- add_officious
- yield self if block_given?
- end
-
- def add_officious # :nodoc:
- list = base()
- Officious.each do |opt, block|
- list.long[opt] ||= block.call(self)
- end
- end
-
- #
- # Terminates option parsing. Optional parameter +arg+ is a string pushed
- # back to be the first non-option argument.
- #
- def terminate(arg = nil)
- self.class.terminate(arg)
- end
- def self.terminate(arg = nil)
- throw :terminate, arg
- end
-
- @stack = [DefaultList]
- def self.top() DefaultList end
-
- #
- # Directs to accept specified class +t+. The argument string is passed to
- # the block in which it should be converted to the desired class.
- #
- # +t+:: Argument class specifier, any object including Class.
- # +pat+:: Pattern for argument, defaults to +t+ if it responds to match.
- #
- # accept(t, pat, &block)
- #
- def accept(*args, &blk) top.accept(*args, &blk) end
- #
- # See #accept.
- #
- def self.accept(*args, &blk) top.accept(*args, &blk) end
-
- #
- # Directs to reject specified class argument.
- #
- # +t+:: Argument class specifier, any object including Class.
- #
- # reject(t)
- #
- def reject(*args, &blk) top.reject(*args, &blk) end
- #
- # See #reject.
- #
- def self.reject(*args, &blk) top.reject(*args, &blk) end
-
- #
- # Instance methods
- #
-
- # Heading banner preceding summary.
- attr_writer :banner
-
- # Program name to be emitted in error message and default banner,
- # defaults to $0.
- attr_writer :program_name
-
- # Width for option list portion of summary. Must be Numeric.
- attr_accessor :summary_width
-
- # Indentation for summary. Must be String (or have + String method).
- attr_accessor :summary_indent
-
- # Strings to be parsed in default.
- attr_accessor :default_argv
-
- # Whether to require that options match exactly (disallows providing
- # abbreviated long option as short option).
- attr_accessor :require_exact
-
- # Whether to raise at unknown option.
- attr_accessor :raise_unknown
-
- #
- # Heading banner preceding summary.
- #
- def banner
- unless @banner
- @banner = +"Usage: #{program_name} [options]"
- visit(:add_banner, @banner)
- end
- @banner
- end
-
- #
- # Program name to be emitted in error message and default banner, defaults
- # to $0.
- #
- def program_name
- @program_name || File.basename($0, '.*')
- end
-
- # for experimental cascading :-)
- alias set_banner banner=
- alias set_program_name program_name=
- alias set_summary_width summary_width=
- alias set_summary_indent summary_indent=
-
- # Version
- attr_writer :version
- # Release code
- attr_writer :release
-
- #
- # Version
- #
- def version
- (defined?(@version) && @version) || (defined?(::Version) && ::Version)
- end
-
- #
- # Release code
- #
- def release
- (defined?(@release) && @release) || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE)
- end
-
- #
- # Returns version string from program_name, version and release.
- #
- def ver
- if v = version
- str = +"#{program_name} #{[v].join('.')}"
- str << " (#{v})" if v = release
- str
- end
- end
-
- def warn(mesg = $!)
- super("#{program_name}: #{mesg}")
- end
-
- def abort(mesg = $!)
- super("#{program_name}: #{mesg}")
- end
-
- #
- # Subject of #on / #on_head, #accept / #reject
- #
- def top
- @stack[-1]
- end
-
- #
- # Subject of #on_tail.
- #
- def base
- @stack[1]
- end
-
- #
- # Pushes a new List.
- #
- def new
- @stack.push(List.new)
- if block_given?
- yield self
- else
- self
- end
- end
-
- #
- # Removes the last List.
- #
- def remove
- @stack.pop
- end
-
- #
- # Puts option summary into +to+ and returns +to+. Yields each line if
- # a block is given.
- #
- # +to+:: Output destination, which must have method <<. Defaults to [].
- # +width+:: Width of left side, defaults to @summary_width.
- # +max+:: Maximum length allowed for left side, defaults to +width+ - 1.
- # +indent+:: Indentation, defaults to @summary_indent.
- #
- def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
- nl = "\n"
- blk ||= proc {|l| to << (l.index(nl, -1) ? l : l + nl)}
- visit(:summarize, {}, {}, width, max, indent, &blk)
- to
- end
-
- #
- # Returns option summary string.
- #
- def help; summarize("#{banner}".sub(/\n?\z/, "\n")) end
- alias to_s help
-
- def pretty_print(q) # :nodoc:
- q.object_group(self) do
- first = true
- if @stack.size > 2
- @stack.each_with_index do |s, i|
- next if i < 2
- next if s.list.empty?
- if first
- first = false
- q.text ":"
- end
- q.breakable
- s.pretty_print(q)
- end
- end
- end
- end
-
- def inspect # :nodoc:
- require 'pp'
- pretty_print_inspect
- end
-
- #
- # Returns option summary list.
- #
- def to_a; summarize("#{banner}".split(/^/)) end
-
- #
- # Checks if an argument is given twice, in which case an ArgumentError is
- # raised. Called from Gem::OptionParser#switch only.
- #
- # +obj+:: New argument.
- # +prv+:: Previously specified argument.
- # +msg+:: Exception message.
- #
- def notwice(obj, prv, msg) # :nodoc:
- unless !prv or prv == obj
- raise(ArgumentError, "argument #{msg} given twice: #{obj}",
- ParseError.filter_backtrace(caller(2)))
- end
- obj
- end
- private :notwice
-
- SPLAT_PROC = proc {|*a| a.length <= 1 ? a.first : a} # :nodoc:
-
- # :call-seq:
- # make_switch(params, block = nil)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def make_switch(opts, block = nil)
- short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], []
- ldesc, sdesc, desc, arg = [], [], []
- default_style = Switch::NoArgument
- default_pattern = nil
- klass = nil
- q, a = nil
- has_arg = false
-
- opts.each do |o|
- # argument class
- next if search(:atype, o) do |pat, c|
- klass = notwice(o, klass, 'type')
- if not_style and not_style != Switch::NoArgument
- not_pattern, not_conv = pat, c
- else
- default_pattern, conv = pat, c
- end
- end
-
- # directly specified pattern(any object possible to match)
- if (!(String === o || Symbol === o)) and o.respond_to?(:match)
- pattern = notwice(o, pattern, 'pattern')
- if pattern.respond_to?(:convert)
- conv = pattern.method(:convert).to_proc
- else
- conv = SPLAT_PROC
- end
- next
- end
-
- # anything others
- case o
- when Proc, Method
- block = notwice(o, block, 'block')
- when Array, Hash
- case pattern
- when CompletingHash
- when nil
- pattern = CompletingHash.new
- conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
- else
- raise ArgumentError, "argument pattern given twice"
- end
- o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
- when Module
- raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4))
- when *ArgumentStyle.keys
- style = notwice(ArgumentStyle[o], style, 'style')
- when /^--no-([^\[\]=\s]*)(.+)?/
- q, a = $1, $2
- o = notwice(a ? Object : TrueClass, klass, 'type')
- not_pattern, not_conv = search(:atype, o) unless not_style
- not_style = (not_style || default_style).guess(arg = a) if a
- default_style = Switch::NoArgument
- default_pattern, conv = search(:atype, FalseClass) unless default_pattern
- ldesc << "--no-#{q}"
- (q = q.downcase).tr!('_', '-')
- long << "no-#{q}"
- nolong << q
- when /^--\[no-\]([^\[\]=\s]*)(.+)?/
- q, a = $1, $2
- o = notwice(a ? Object : TrueClass, klass, 'type')
- if a
- default_style = default_style.guess(arg = a)
- default_pattern, conv = search(:atype, o) unless default_pattern
- end
- ldesc << "--[no-]#{q}"
- (o = q.downcase).tr!('_', '-')
- long << o
- not_pattern, not_conv = search(:atype, FalseClass) unless not_style
- not_style = Switch::NoArgument
- nolong << "no-#{o}"
- when /^--([^\[\]=\s]*)(.+)?/
- q, a = $1, $2
- if a
- o = notwice(NilClass, klass, 'type')
- default_style = default_style.guess(arg = a)
- default_pattern, conv = search(:atype, o) unless default_pattern
- end
- ldesc << "--#{q}"
- (o = q.downcase).tr!('_', '-')
- long << o
- when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
- q, a = $1, $2
- o = notwice(Object, klass, 'type')
- if a
- default_style = default_style.guess(arg = a)
- default_pattern, conv = search(:atype, o) unless default_pattern
- else
- has_arg = true
- end
- sdesc << "-#{q}"
- short << Regexp.new(q)
- when /^-(.)(.+)?/
- q, a = $1, $2
- if a
- o = notwice(NilClass, klass, 'type')
- default_style = default_style.guess(arg = a)
- default_pattern, conv = search(:atype, o) unless default_pattern
- end
- sdesc << "-#{q}"
- short << q
- when /^=/
- style = notwice(default_style.guess(arg = o), style, 'style')
- default_pattern, conv = search(:atype, Object) unless default_pattern
- else
- desc.push(o) if o && !o.empty?
- end
- end
-
- default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
- if !(short.empty? and long.empty?)
- if has_arg and default_style == Switch::NoArgument
- default_style = Switch::RequiredArgument
- end
- s = (style || default_style).new(pattern || default_pattern,
- conv, sdesc, ldesc, arg, desc, block)
- elsif !block
- if style or pattern
- raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
- end
- s = desc
- else
- short << pattern
- s = (style || default_style).new(pattern,
- conv, nil, nil, arg, desc, block)
- end
- return s, short, long,
- (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
- nolong
- end
-
- # :call-seq:
- # define(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def define(*opts, &block)
- top.append(*(sw = make_switch(opts, block)))
- sw[0]
- end
-
- # :call-seq:
- # on(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def on(*opts, &block)
- define(*opts, &block)
- self
- end
- alias def_option define
-
- # :call-seq:
- # define_head(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def define_head(*opts, &block)
- top.prepend(*(sw = make_switch(opts, block)))
- sw[0]
- end
-
- # :call-seq:
- # on_head(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- # The new option is added at the head of the summary.
- #
- def on_head(*opts, &block)
- define_head(*opts, &block)
- self
- end
- alias def_head_option define_head
-
- # :call-seq:
- # define_tail(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def define_tail(*opts, &block)
- base.append(*(sw = make_switch(opts, block)))
- sw[0]
- end
-
- #
- # :call-seq:
- # on_tail(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- # The new option is added at the tail of the summary.
- #
- def on_tail(*opts, &block)
- define_tail(*opts, &block)
- self
- end
- alias def_tail_option define_tail
-
- #
- # Add separator in summary.
- #
- def separator(string)
- top.append(string, nil, nil)
- end
-
- #
- # Parses command line arguments +argv+ in order. When a block is given,
- # each non-option argument is yielded. When optional +into+ keyword
- # argument is provided, the parsed option values are stored there via
- # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
- # similar object).
- #
- # Returns the rest of +argv+ left unparsed.
- #
- def order(*argv, into: nil, &nonopt)
- argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- order!(argv, into: into, &nonopt)
- end
-
- #
- # Same as #order, but removes switches destructively.
- # Non-option arguments remain in +argv+.
- #
- def order!(argv = default_argv, into: nil, &nonopt)
- setter = ->(name, val) {into[name.to_sym] = val} if into
- parse_in_order(argv, setter, &nonopt)
- end
-
- def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
- opt, arg, val, rest = nil
- nonopt ||= proc {|a| throw :terminate, a}
- argv.unshift(arg) if arg = catch(:terminate) {
- while arg = argv.shift
- case arg
- # long option
- when /\A--([^=]*)(?:=(.*))?/m
- opt, rest = $1, $2
- opt.tr!('_', '-')
- begin
- sw, = complete(:long, opt, true)
- if require_exact && !sw.long.include?(arg)
- throw :terminate, arg unless raise_unknown
- raise InvalidOption, arg
- end
- rescue ParseError
- throw :terminate, arg unless raise_unknown
- raise $!.set_option(arg, true)
- end
- begin
- opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
- val = cb.call(val) if cb
- setter.call(sw.switch_name, val) if setter
- rescue ParseError
- raise $!.set_option(arg, rest)
- end
-
- # short option
- when /\A-(.)((=).*|.+)?/m
- eq, rest, opt = $3, $2, $1
- has_arg, val = eq, rest
- begin
- sw, = search(:short, opt)
- unless sw
- begin
- sw, = complete(:short, opt)
- # short option matched.
- val = arg.delete_prefix('-')
- has_arg = true
- rescue InvalidOption
- raise if require_exact
- # if no short options match, try completion with long
- # options.
- sw, = complete(:long, opt)
- eq ||= !rest
- end
- end
- rescue ParseError
- throw :terminate, arg unless raise_unknown
- raise $!.set_option(arg, true)
- end
- begin
- opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
- rescue ParseError
- raise $!.set_option(arg, arg.length > 2)
- else
- raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
- end
- begin
- argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
- val = cb.call(val) if cb
- setter.call(sw.switch_name, val) if setter
- rescue ParseError
- raise $!.set_option(arg, arg.length > 2)
- end
-
- # non-option argument
- else
- catch(:prune) do
- visit(:each_option) do |sw0|
- sw = sw0
- sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg)
- end
- nonopt.call(arg)
- end
- end
- end
-
- nil
- }
-
- visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
-
- argv
- end
- private :parse_in_order
-
- #
- # Parses command line arguments +argv+ in permutation mode and returns
- # list of non-option arguments. When optional +into+ keyword
- # argument is provided, the parsed option values are stored there via
- # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
- # similar object).
- #
- def permute(*argv, into: nil)
- argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- permute!(argv, into: into)
- end
-
- #
- # Same as #permute, but removes switches destructively.
- # Non-option arguments remain in +argv+.
- #
- def permute!(argv = default_argv, into: nil)
- nonopts = []
- order!(argv, into: into, &nonopts.method(:<<))
- argv[0, 0] = nonopts
- argv
- end
-
- #
- # Parses command line arguments +argv+ in order when environment variable
- # POSIXLY_CORRECT is set, and in permutation mode otherwise.
- # When optional +into+ keyword argument is provided, the parsed option
- # values are stored there via <code>[]=</code> method (so it can be Hash,
- # or OpenStruct, or other similar object).
- #
- def parse(*argv, into: nil)
- argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- parse!(argv, into: into)
- end
-
- #
- # Same as #parse, but removes switches destructively.
- # Non-option arguments remain in +argv+.
- #
- def parse!(argv = default_argv, into: nil)
- if ENV.include?('POSIXLY_CORRECT')
- order!(argv, into: into)
- else
- permute!(argv, into: into)
- end
- end
-
- #
- # Wrapper method for getopts.rb.
- #
- # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option")
- # # params["a"] = true # -a
- # # params["b"] = "1" # -b1
- # # params["foo"] = "1" # --foo
- # # 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)
- argv = Array === args.first ? args.shift : default_argv
- single_options, *long_options = *args
-
- result = {}
-
- single_options.scan(/(.)(:)?/) do |opt, val|
- if val
- result[opt] = nil
- define("-#{opt} VAL")
- else
- result[opt] = false
- define("-#{opt}")
- end
- end if single_options
-
- long_options.each do |arg|
- arg, desc = arg.split(';', 2)
- opt, val = arg.split(':', 2)
- if val
- result[opt] = val.empty? ? nil : val
- define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
- else
- result[opt] = false
- define("--#{opt}", *[desc].compact)
- end
- end
-
- parse_in_order(argv, result.method(:[]=))
- symbolize_names ? result.transform_keys(&:to_sym) : result
- end
-
- #
- # See #getopts.
- #
- def self.getopts(*args, symbolize_names: false)
- new.getopts(*args, symbolize_names: symbolize_names)
- end
-
- #
- # Traverses @stack, sending each element method +id+ with +args+ and
- # +block+.
- #
- def visit(id, *args, &block) # :nodoc:
- @stack.reverse_each do |el|
- el.__send__(id, *args, &block)
- end
- nil
- end
- private :visit
-
- #
- # Searches +key+ in @stack for +id+ hash and returns or yields the result.
- #
- def search(id, key) # :nodoc:
- block_given = block_given?
- visit(:search, id, key) do |k|
- return block_given ? yield(k) : k
- end
- end
- private :search
-
- #
- # Completes shortened long style option switch and returns pair of
- # canonical switch and switch descriptor Gem::OptionParser::Switch.
- #
- # +typ+:: Searching table.
- # +opt+:: Searching key.
- # +icase+:: Search case insensitive if true.
- # +pat+:: Optional pattern for completion.
- #
- def complete(typ, opt, icase = false, *pat) # :nodoc:
- if pat.empty?
- search(typ, opt) {|sw| return [sw, opt]} # exact match or...
- end
- ambiguous = catch(:ambiguous) {
- visit(:complete, typ, opt, icase, *pat) {|o, *sw| return sw}
- }
- exc = ambiguous ? AmbiguousOption : InvalidOption
- raise exc.new(opt, additional: self.method(:additional_message).curry[typ])
- end
- private :complete
-
- #
- # Returns additional info.
- #
- def additional_message(typ, opt)
- return unless typ and opt and defined?(DidYouMean::SpellChecker)
- all_candidates = []
- visit(:get_candidates, typ) do |candidates|
- all_candidates.concat(candidates)
- end
- all_candidates.select! {|cand| cand.is_a?(String) }
- checker = DidYouMean::SpellChecker.new(dictionary: all_candidates)
- DidYouMean.formatter.message_for(all_candidates & checker.correct(opt))
- end
-
- def candidate(word)
- list = []
- case word
- when '-'
- long = short = true
- when /\A--/
- word, arg = word.split(/=/, 2)
- argpat = Completion.regexp(arg, false) if arg and !arg.empty?
- long = true
- when /\A-/
- short = true
- end
- pat = Completion.regexp(word, long)
- visit(:each_option) do |opt|
- next unless Switch === opt
- opts = (long ? opt.long : []) + (short ? opt.short : [])
- opts = Completion.candidate(word, true, pat, &opts.method(:each)).map(&:first) if pat
- if /\A=/ =~ opt.arg
- opts.map! {|sw| sw + "="}
- if arg and CompletingHash === opt.pattern
- if opts = opt.pattern.candidate(arg, false, argpat)
- opts.map!(&:last)
- end
- end
- end
- list.concat(opts)
- end
- list
- end
-
- #
- # Loads options from file names as +filename+. Does nothing when the file
- # is not present. Returns whether successfully loaded.
- #
- # +filename+ defaults to basename of the program without suffix in a
- # directory ~/.options, then the basename with '.options' suffix
- # under XDG and Haiku standard places.
- #
- # The optional +into+ keyword argument works exactly like that accepted in
- # method #parse.
- #
- def load(filename = nil, into: nil)
- unless filename
- basename = File.basename($0, '.*')
- return true if load(File.expand_path(basename, '~/.options'), into: into) rescue nil
- basename << ".options"
- return [
- # XDG
- ENV['XDG_CONFIG_HOME'],
- '~/.config',
- *ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
-
- # Haiku
- '~/config/settings',
- ].any? {|dir|
- next if !dir or dir.empty?
- load(File.expand_path(basename, dir), into: into) rescue nil
- }
- end
- begin
- parse(*File.readlines(filename, chomp: true), into: into)
- true
- rescue Errno::ENOENT, Errno::ENOTDIR
- false
- end
- end
-
- #
- # Parses environment variable +env+ or its uppercase with splitting like a
- # shell.
- #
- # +env+ defaults to the basename of the program.
- #
- def environment(env = File.basename($0, '.*'))
- env = ENV[env] || ENV[env.upcase] or return
- require 'shellwords'
- parse(*Shellwords.shellwords(env))
- end
-
- #
- # Acceptable argument classes
- #
-
- #
- # Any string and no conversion. This is fall-back.
- #
- accept(Object) {|s,|s or s.nil?}
-
- accept(NilClass) {|s,|s}
-
- #
- # Any non-empty string, and no conversion.
- #
- accept(String, /.+/m) {|s,*|s}
-
- #
- # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal
- # for 0x, and decimal for others; with optional sign prefix. Converts to
- # Integer.
- #
- decimal = '\d+(?:_\d+)*'
- binary = 'b[01]+(?:_[01]+)*'
- hex = 'x[\da-f]+(?:_[\da-f]+)*'
- octal = "0(?:[0-7]+(?:_[0-7]+)*|#{binary}|#{hex})?"
- integer = "#{octal}|#{decimal}"
-
- accept(Integer, %r"\A[-+]?(?:#{integer})\z"io) {|s,|
- begin
- Integer(s)
- rescue ArgumentError
- raise Gem::OptionParser::InvalidArgument, s
- end if s
- }
-
- #
- # Float number format, and converts to Float.
- #
- float = "(?:#{decimal}(?=(.)?)(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?"
- floatpat = %r"\A[-+]?#{float}\z"io
- accept(Float, floatpat) {|s,| s.to_f if s}
-
- #
- # Generic numeric format, converts to Integer for integer format, Float
- # for float format, and Rational for rational format.
- #
- real = "[-+]?(?:#{octal}|#{float})"
- accept(Numeric, /\A(#{real})(?:\/(#{real}))?\z/io) {|s, d, f, n,|
- if n
- Rational(d, n)
- elsif f
- Float(s)
- else
- Integer(s)
- end
- }
-
- #
- # Decimal integer format, to be converted to Integer.
- #
- DecimalInteger = /\A[-+]?#{decimal}\z/io
- accept(DecimalInteger, DecimalInteger) {|s,|
- begin
- Integer(s, 10)
- rescue ArgumentError
- raise Gem::OptionParser::InvalidArgument, s
- end if s
- }
-
- #
- # Ruby/C like octal/hexadecimal/binary integer format, to be converted to
- # Integer.
- #
- OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))\z/io
- accept(OctalInteger, OctalInteger) {|s,|
- begin
- Integer(s, 8)
- rescue ArgumentError
- raise Gem::OptionParser::InvalidArgument, s
- end if s
- }
-
- #
- # Decimal integer/float number format, to be converted to Integer for
- # integer format, Float for float format.
- #
- DecimalNumeric = floatpat # decimal integer is allowed as float also.
- accept(DecimalNumeric, floatpat) {|s, f|
- begin
- if f
- Float(s)
- else
- Integer(s)
- end
- rescue ArgumentError
- raise Gem::OptionParser::InvalidArgument, s
- end if s
- }
-
- #
- # Boolean switch, which means whether it is present or not, whether it is
- # absent or not with prefix no-, or it takes an argument
- # yes/no/true/false/+/-.
- #
- yesno = CompletingHash.new
- %w[- no false].each {|el| yesno[el] = false}
- %w[+ yes true].each {|el| yesno[el] = true}
- yesno['nil'] = false # should be nil?
- accept(TrueClass, yesno) {|arg, val| val == nil or val}
- #
- # Similar to TrueClass, but defaults to false.
- #
- accept(FalseClass, yesno) {|arg, val| val != nil and val}
-
- #
- # List of strings separated by ",".
- #
- accept(Array) do |s, |
- if s
- s = s.split(',').collect {|ss| ss unless ss.empty?}
- end
- s
- end
-
- #
- # Regular expression with options.
- #
- accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o|
- f = 0
- if o
- f |= Regexp::IGNORECASE if /i/ =~ o
- f |= Regexp::MULTILINE if /m/ =~ o
- f |= Regexp::EXTENDED if /x/ =~ o
- case o = o.delete("imx")
- when ""
- when "u"
- s = s.encode(Encoding::UTF_8)
- when "e"
- s = s.encode(Encoding::EUC_JP)
- when "s"
- s = s.encode(Encoding::SJIS)
- when "n"
- f |= Regexp::NOENCODING
- else
- raise Gem::OptionParser::InvalidArgument, "unknown regexp option - #{o}"
- end
- else
- s ||= all
- end
- Regexp.new(s, f)
- end
-
- #
- # Exceptions
- #
-
- #
- # Base class of exceptions from Gem::OptionParser.
- #
- class ParseError < RuntimeError
- # Reason which caused the error.
- Reason = 'parse error'
-
- def initialize(*args, additional: nil)
- @additional = additional
- @arg0, = args
- @args = args
- @reason = nil
- end
-
- attr_reader :args
- attr_writer :reason
- attr_accessor :additional
-
- #
- # Pushes back erred argument(s) to +argv+.
- #
- def recover(argv)
- argv[0, 0] = @args
- argv
- end
-
- def self.filter_backtrace(array)
- unless $DEBUG
- array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
- end
- array
- end
-
- def set_backtrace(array)
- super(self.class.filter_backtrace(array))
- end
-
- def set_option(opt, eq)
- if eq
- @args[0] = opt
- else
- @args.unshift(opt)
- end
- self
- end
-
- #
- # Returns error reason. Override this for I18N.
- #
- def reason
- @reason || self.class::Reason
- end
-
- def inspect
- "#<#{self.class}: #{args.join(' ')}>"
- end
-
- #
- # Default stringizing method to emit standard error message.
- #
- def message
- "#{reason}: #{args.join(' ')}#{additional[@arg0] if additional}"
- end
-
- alias to_s message
- end
-
- #
- # Raises when ambiguously completable string is encountered.
- #
- class AmbiguousOption < ParseError
- const_set(:Reason, 'ambiguous option')
- end
-
- #
- # Raises when there is an argument for a switch which takes no argument.
- #
- class NeedlessArgument < ParseError
- const_set(:Reason, 'needless argument')
- end
-
- #
- # Raises when a switch with mandatory argument has no argument.
- #
- class MissingArgument < ParseError
- const_set(:Reason, 'missing argument')
- end
-
- #
- # Raises when switch is undefined.
- #
- class InvalidOption < ParseError
- const_set(:Reason, 'invalid option')
- end
-
- #
- # Raises when the given argument does not match required format.
- #
- class InvalidArgument < ParseError
- const_set(:Reason, 'invalid argument')
- end
-
- #
- # Raises when the given argument word can't be completed uniquely.
- #
- class AmbiguousArgument < InvalidArgument
- const_set(:Reason, 'ambiguous argument')
- end
-
- #
- # Miscellaneous
- #
-
- #
- # Extends command line arguments array (ARGV) to parse itself.
- #
- module Arguable
-
- #
- # Sets Gem::OptionParser object, when +opt+ is +false+ or +nil+, methods
- # Gem::OptionParser::Arguable#options and Gem::OptionParser::Arguable#options= are
- # undefined. Thus, there is no ways to access the Gem::OptionParser object
- # via the receiver object.
- #
- def options=(opt)
- unless @optparse = opt
- class << self
- undef_method(:options)
- undef_method(:options=)
- end
- end
- end
-
- #
- # Actual Gem::OptionParser object, automatically created if nonexistent.
- #
- # If called with a block, yields the Gem::OptionParser object and returns the
- # result of the block. If an Gem::OptionParser::ParseError exception occurs
- # in the block, it is rescued, a error message printed to STDERR and
- # +nil+ returned.
- #
- def options
- @optparse ||= Gem::OptionParser.new
- @optparse.default_argv = self
- block_given? or return @optparse
- begin
- yield @optparse
- rescue ParseError
- @optparse.warn $!
- nil
- end
- end
-
- #
- # Parses +self+ destructively in order and returns +self+ containing the
- # rest arguments left unparsed.
- #
- def order!(&blk) options.order!(self, &blk) end
-
- #
- # Parses +self+ destructively in permutation mode and returns +self+
- # containing the rest arguments left unparsed.
- #
- def permute!() options.permute!(self) end
-
- #
- # Parses +self+ destructively and returns +self+ containing the
- # rest arguments left unparsed.
- #
- def parse!() options.parse!(self) end
-
- #
- # Substitution of getopts is possible as follows. Also see
- # Gem::OptionParser#getopts.
- #
- # def getopts(*args)
- # ($OPT = ARGV.getopts(*args)).each do |opt, val|
- # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val"
- # end
- # rescue Gem::OptionParser::ParseError
- # end
- #
- def getopts(*args, symbolize_names: false)
- options.getopts(self, *args, symbolize_names: symbolize_names)
- end
-
- #
- # Initializes instance variable.
- #
- def self.extend_object(obj)
- super
- obj.instance_eval {@optparse = nil}
- end
- def initialize(*args)
- super
- @optparse = nil
- end
- end
-
- #
- # Acceptable argument classes. Now contains DecimalInteger, OctalInteger
- # and DecimalNumeric. See Acceptable argument classes (in source code).
- #
- module Acceptables
- const_set(:DecimalInteger, Gem::OptionParser::DecimalInteger)
- const_set(:OctalInteger, Gem::OptionParser::OctalInteger)
- const_set(:DecimalNumeric, Gem::OptionParser::DecimalNumeric)
- end
-end
-
-# ARGV is arguable by Gem::OptionParser
-ARGV.extend(Gem::OptionParser::Arguable)
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/uri.rb b/lib/rubygems/vendor/optparse/lib/optparse/uri.rb
deleted file mode 100644
index 398127479a..0000000000
--- a/lib/rubygems/vendor/optparse/lib/optparse/uri.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: false
-# -*- ruby -*-
-
-require_relative '../optparse'
-require_relative '../../../uri/lib/uri'
-
-Gem::OptionParser.accept(Gem::URI) {|s,| Gem::URI.parse(s) if s}
diff --git a/lib/rubygems/vendor/resolv/.document b/lib/rubygems/vendor/resolv/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/resolv/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/resolv/lib/resolv.rb b/lib/rubygems/vendor/resolv/lib/resolv.rb
deleted file mode 100644
index 0f5ded3b76..0000000000
--- a/lib/rubygems/vendor/resolv/lib/resolv.rb
+++ /dev/null
@@ -1,3442 +0,0 @@
-# frozen_string_literal: true
-
-require 'socket'
-require_relative '../../timeout/lib/timeout'
-require 'io/wait'
-
-begin
- require_relative '../../../vendored_securerandom'
-rescue LoadError
-end
-
-# Gem::Resolv is a thread-aware DNS resolver library written in Ruby. Gem::Resolv can
-# handle multiple DNS requests concurrently without blocking the entire Ruby
-# interpreter.
-#
-# See also resolv-replace.rb to replace the libc resolver with Gem::Resolv.
-#
-# Gem::Resolv can look up various DNS resources using the DNS module directly.
-#
-# Examples:
-#
-# p Gem::Resolv.getaddress "www.ruby-lang.org"
-# p Gem::Resolv.getname "210.251.121.214"
-#
-# Gem::Resolv::DNS.open do |dns|
-# ress = dns.getresources "www.ruby-lang.org", Gem::Resolv::DNS::Resource::IN::A
-# p ress.map(&:address)
-# ress = dns.getresources "ruby-lang.org", Gem::Resolv::DNS::Resource::IN::MX
-# p ress.map { |r| [r.exchange.to_s, r.preference] }
-# end
-#
-#
-# == Bugs
-#
-# * NIS is not supported.
-# * /etc/nsswitch.conf is not supported.
-
-class Gem::Resolv
-
- VERSION = "0.4.0"
-
- ##
- # Looks up the first IP address for +name+.
-
- def self.getaddress(name)
- DefaultResolver.getaddress(name)
- end
-
- ##
- # Looks up all IP address for +name+.
-
- def self.getaddresses(name)
- DefaultResolver.getaddresses(name)
- end
-
- ##
- # Iterates over all IP addresses for +name+.
-
- def self.each_address(name, &block)
- DefaultResolver.each_address(name, &block)
- end
-
- ##
- # Looks up the hostname of +address+.
-
- def self.getname(address)
- DefaultResolver.getname(address)
- end
-
- ##
- # Looks up all hostnames for +address+.
-
- def self.getnames(address)
- DefaultResolver.getnames(address)
- end
-
- ##
- # Iterates over all hostnames for +address+.
-
- def self.each_name(address, &proc)
- DefaultResolver.each_name(address, &proc)
- end
-
- ##
- # Creates a new Gem::Resolv using +resolvers+.
-
- def initialize(resolvers=nil, use_ipv6: nil)
- @resolvers = resolvers || [Hosts.new, DNS.new(DNS::Config.default_config_hash.merge(use_ipv6: use_ipv6))]
- end
-
- ##
- # Looks up the first IP address for +name+.
-
- def getaddress(name)
- each_address(name) {|address| return address}
- raise ResolvError.new("no address for #{name}")
- end
-
- ##
- # Looks up all IP address for +name+.
-
- def getaddresses(name)
- ret = []
- each_address(name) {|address| ret << address}
- return ret
- end
-
- ##
- # Iterates over all IP addresses for +name+.
-
- def each_address(name)
- if AddressRegex =~ name
- yield name
- return
- end
- yielded = false
- @resolvers.each {|r|
- r.each_address(name) {|address|
- yield address.to_s
- yielded = true
- }
- return if yielded
- }
- end
-
- ##
- # Looks up the hostname of +address+.
-
- def getname(address)
- each_name(address) {|name| return name}
- raise ResolvError.new("no name for #{address}")
- end
-
- ##
- # Looks up all hostnames for +address+.
-
- def getnames(address)
- ret = []
- each_name(address) {|name| ret << name}
- return ret
- end
-
- ##
- # Iterates over all hostnames for +address+.
-
- def each_name(address)
- yielded = false
- @resolvers.each {|r|
- r.each_name(address) {|name|
- yield name.to_s
- yielded = true
- }
- return if yielded
- }
- end
-
- ##
- # Indicates a failure to resolve a name or address.
-
- class ResolvError < StandardError; end
-
- ##
- # Indicates a timeout resolving a name or address.
-
- class ResolvTimeout < Gem::Timeout::Error; end
-
- ##
- # Gem::Resolv::Hosts is a hostname resolver that uses the system hosts file.
-
- class Hosts
- if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM and
- begin
- require 'win32/resolv'
- DefaultFileName = Win32::Resolv.get_hosts_path || IO::NULL
- rescue LoadError
- end
- end
- DefaultFileName ||= '/etc/hosts'
-
- ##
- # Creates a new Gem::Resolv::Hosts, using +filename+ for its data source.
-
- def initialize(filename = DefaultFileName)
- @filename = filename
- @mutex = Thread::Mutex.new
- @initialized = nil
- end
-
- def lazy_initialize # :nodoc:
- @mutex.synchronize {
- unless @initialized
- @name2addr = {}
- @addr2name = {}
- File.open(@filename, 'rb') {|f|
- f.each {|line|
- line.sub!(/#.*/, '')
- addr, *hostnames = line.split(/\s+/)
- next unless addr
- (@addr2name[addr] ||= []).concat(hostnames)
- hostnames.each {|hostname| (@name2addr[hostname] ||= []) << addr}
- }
- }
- @name2addr.each {|name, arr| arr.reverse!}
- @initialized = true
- end
- }
- self
- end
-
- ##
- # Gets the IP address of +name+ from the hosts file.
-
- def getaddress(name)
- each_address(name) {|address| return address}
- raise ResolvError.new("#{@filename} has no name: #{name}")
- end
-
- ##
- # Gets all IP addresses for +name+ from the hosts file.
-
- def getaddresses(name)
- ret = []
- each_address(name) {|address| ret << address}
- return ret
- end
-
- ##
- # Iterates over all IP addresses for +name+ retrieved from the hosts file.
-
- def each_address(name, &proc)
- lazy_initialize
- @name2addr[name]&.each(&proc)
- end
-
- ##
- # Gets the hostname of +address+ from the hosts file.
-
- def getname(address)
- each_name(address) {|name| return name}
- raise ResolvError.new("#{@filename} has no address: #{address}")
- end
-
- ##
- # Gets all hostnames for +address+ from the hosts file.
-
- def getnames(address)
- ret = []
- each_name(address) {|name| ret << name}
- return ret
- end
-
- ##
- # Iterates over all hostnames for +address+ retrieved from the hosts file.
-
- def each_name(address, &proc)
- lazy_initialize
- @addr2name[address]&.each(&proc)
- end
- end
-
- ##
- # Gem::Resolv::DNS is a DNS stub resolver.
- #
- # Information taken from the following places:
- #
- # * STD0013
- # * RFC 1035
- # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
- # * etc.
-
- class DNS
-
- ##
- # Default DNS Port
-
- Port = 53
-
- ##
- # Default DNS UDP packet size
-
- UDPSize = 512
-
- ##
- # Creates a new DNS resolver. See Gem::Resolv::DNS.new for argument details.
- #
- # Yields the created DNS resolver to the block, if given, otherwise
- # returns it.
-
- def self.open(*args)
- dns = new(*args)
- return dns unless block_given?
- begin
- yield dns
- ensure
- dns.close
- end
- end
-
- ##
- # Creates a new DNS resolver.
- #
- # +config_info+ can be:
- #
- # nil:: Uses /etc/resolv.conf.
- # String:: Path to a file using /etc/resolv.conf's format.
- # Hash:: Must contain :nameserver, :search and :ndots keys.
- # :nameserver_port can be used to specify port number of nameserver address.
- # :raise_timeout_errors can be used to raise timeout errors
- # as exceptions instead of treating the same as an NXDOMAIN response.
- #
- # The value of :nameserver should be an address string or
- # an array of address strings.
- # - :nameserver => '8.8.8.8'
- # - :nameserver => ['8.8.8.8', '8.8.4.4']
- #
- # The value of :nameserver_port should be an array of
- # pair of nameserver address and port number.
- # - :nameserver_port => [['8.8.8.8', 53], ['8.8.4.4', 53]]
- #
- # Example:
- #
- # Gem::Resolv::DNS.new(:nameserver => ['210.251.121.21'],
- # :search => ['ruby-lang.org'],
- # :ndots => 1)
-
- def initialize(config_info=nil)
- @mutex = Thread::Mutex.new
- @config = Config.new(config_info)
- @initialized = nil
- end
-
- # Sets the resolver timeouts. This may be a single positive number
- # or an array of positive numbers representing timeouts in seconds.
- # If an array is specified, a DNS request will retry and wait for
- # each successive interval in the array until a successful response
- # is received. Specifying +nil+ reverts to the default timeouts:
- # [ 5, second = 5 * 2 / nameserver_count, 2 * second, 4 * second ]
- #
- # Example:
- #
- # dns.timeouts = 3
- #
- def timeouts=(values)
- @config.timeouts = values
- end
-
- def lazy_initialize # :nodoc:
- @mutex.synchronize {
- unless @initialized
- @config.lazy_initialize
- @initialized = true
- end
- }
- self
- end
-
- ##
- # Closes the DNS resolver.
-
- def close
- @mutex.synchronize {
- if @initialized
- @initialized = false
- end
- }
- end
-
- ##
- # Gets the IP address of +name+ from the DNS resolver.
- #
- # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved address will
- # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
-
- def getaddress(name)
- each_address(name) {|address| return address}
- raise ResolvError.new("DNS result has no information for #{name}")
- end
-
- ##
- # Gets all IP addresses for +name+ from the DNS resolver.
- #
- # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved addresses will
- # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
-
- def getaddresses(name)
- ret = []
- each_address(name) {|address| ret << address}
- return ret
- end
-
- ##
- # Iterates over all IP addresses for +name+ retrieved from the DNS
- # resolver.
- #
- # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved addresses will
- # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
-
- def each_address(name)
- each_resource(name, Resource::IN::A) {|resource| yield resource.address}
- if use_ipv6?
- each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
- end
- end
-
- def use_ipv6? # :nodoc:
- use_ipv6 = @config.use_ipv6?
- unless use_ipv6.nil?
- return use_ipv6
- end
-
- begin
- list = Socket.ip_address_list
- rescue NotImplementedError
- return true
- end
- list.any? {|a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
- end
- private :use_ipv6?
-
- ##
- # Gets the hostname for +address+ from the DNS resolver.
- #
- # +address+ must be a Gem::Resolv::IPv4, Gem::Resolv::IPv6 or a String. Retrieved
- # name will be a Gem::Resolv::DNS::Name.
-
- def getname(address)
- each_name(address) {|name| return name}
- raise ResolvError.new("DNS result has no information for #{address}")
- end
-
- ##
- # Gets all hostnames for +address+ from the DNS resolver.
- #
- # +address+ must be a Gem::Resolv::IPv4, Gem::Resolv::IPv6 or a String. Retrieved
- # names will be Gem::Resolv::DNS::Name instances.
-
- def getnames(address)
- ret = []
- each_name(address) {|name| ret << name}
- return ret
- end
-
- ##
- # Iterates over all hostnames for +address+ retrieved from the DNS
- # resolver.
- #
- # +address+ must be a Gem::Resolv::IPv4, Gem::Resolv::IPv6 or a String. Retrieved
- # names will be Gem::Resolv::DNS::Name instances.
-
- def each_name(address)
- case address
- when Name
- ptr = address
- when IPv4, IPv6
- ptr = address.to_name
- when IPv4::Regex
- ptr = IPv4.create(address).to_name
- when IPv6::Regex
- ptr = IPv6.create(address).to_name
- else
- raise ResolvError.new("cannot interpret as address: #{address}")
- end
- each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name}
- end
-
- ##
- # Look up the +typeclass+ DNS resource of +name+.
- #
- # +name+ must be a Gem::Resolv::DNS::Name or a String.
- #
- # +typeclass+ should be one of the following:
- #
- # * Gem::Resolv::DNS::Resource::IN::A
- # * Gem::Resolv::DNS::Resource::IN::AAAA
- # * Gem::Resolv::DNS::Resource::IN::ANY
- # * Gem::Resolv::DNS::Resource::IN::CNAME
- # * Gem::Resolv::DNS::Resource::IN::HINFO
- # * Gem::Resolv::DNS::Resource::IN::MINFO
- # * Gem::Resolv::DNS::Resource::IN::MX
- # * Gem::Resolv::DNS::Resource::IN::NS
- # * Gem::Resolv::DNS::Resource::IN::PTR
- # * Gem::Resolv::DNS::Resource::IN::SOA
- # * Gem::Resolv::DNS::Resource::IN::TXT
- # * Gem::Resolv::DNS::Resource::IN::WKS
- #
- # Returned resource is represented as a Gem::Resolv::DNS::Resource instance,
- # i.e. Gem::Resolv::DNS::Resource::IN::A.
-
- def getresource(name, typeclass)
- each_resource(name, typeclass) {|resource| return resource}
- raise ResolvError.new("DNS result has no information for #{name}")
- end
-
- ##
- # Looks up all +typeclass+ DNS resources for +name+. See #getresource for
- # argument details.
-
- def getresources(name, typeclass)
- ret = []
- each_resource(name, typeclass) {|resource| ret << resource}
- return ret
- end
-
- ##
- # Iterates over all +typeclass+ DNS resources for +name+. See
- # #getresource for argument details.
-
- def each_resource(name, typeclass, &proc)
- fetch_resource(name, typeclass) {|reply, reply_name|
- extract_resources(reply, reply_name, typeclass, &proc)
- }
- end
-
- def fetch_resource(name, typeclass)
- lazy_initialize
- begin
- requester = make_udp_requester
- rescue Errno::EACCES
- # fall back to TCP
- end
- senders = {}
- begin
- @config.resolv(name) {|candidate, tout, nameserver, port|
- requester ||= make_tcp_requester(nameserver, port)
- msg = Message.new
- msg.rd = 1
- msg.add_question(candidate, typeclass)
- unless sender = senders[[candidate, nameserver, port]]
- sender = requester.sender(msg, candidate, nameserver, port)
- next if !sender
- senders[[candidate, nameserver, port]] = sender
- end
- reply, reply_name = requester.request(sender, tout)
- case reply.rcode
- when RCode::NoError
- if reply.tc == 1 and not Requester::TCP === requester
- requester.close
- # Retry via TCP:
- requester = make_tcp_requester(nameserver, port)
- senders = {}
- # This will use TCP for all remaining candidates (assuming the
- # current candidate does not already respond successfully via
- # TCP). This makes sense because we already know the full
- # response will not fit in an untruncated UDP packet.
- redo
- else
- yield(reply, reply_name)
- end
- return
- when RCode::NXDomain
- raise Config::NXDomain.new(reply_name.to_s)
- else
- raise Config::OtherResolvError.new(reply_name.to_s)
- end
- }
- ensure
- requester&.close
- end
- end
-
- def make_udp_requester # :nodoc:
- nameserver_port = @config.nameserver_port
- if nameserver_port.length == 1
- Requester::ConnectedUDP.new(*nameserver_port[0])
- else
- Requester::UnconnectedUDP.new(*nameserver_port)
- end
- end
-
- def make_tcp_requester(host, port) # :nodoc:
- return Requester::TCP.new(host, port)
- end
-
- def extract_resources(msg, name, typeclass) # :nodoc:
- if typeclass < Resource::ANY
- n0 = Name.create(name)
- msg.each_resource {|n, ttl, data|
- yield data if n0 == n
- }
- end
- yielded = false
- n0 = Name.create(name)
- msg.each_resource {|n, ttl, data|
- if n0 == n
- case data
- when typeclass
- yield data
- yielded = true
- when Resource::CNAME
- n0 = data.name
- end
- end
- }
- return if yielded
- msg.each_resource {|n, ttl, data|
- if n0 == n
- case data
- when typeclass
- yield data
- end
- end
- }
- end
-
- if defined? Gem::SecureRandom
- def self.random(arg) # :nodoc:
- begin
- Gem::SecureRandom.random_number(arg)
- rescue NotImplementedError
- rand(arg)
- end
- end
- else
- def self.random(arg) # :nodoc:
- rand(arg)
- end
- end
-
- RequestID = {} # :nodoc:
- RequestIDMutex = Thread::Mutex.new # :nodoc:
-
- def self.allocate_request_id(host, port) # :nodoc:
- id = nil
- RequestIDMutex.synchronize {
- h = (RequestID[[host, port]] ||= {})
- begin
- id = random(0x0000..0xffff)
- end while h[id]
- h[id] = true
- }
- id
- end
-
- def self.free_request_id(host, port, id) # :nodoc:
- RequestIDMutex.synchronize {
- key = [host, port]
- if h = RequestID[key]
- h.delete id
- if h.empty?
- RequestID.delete key
- end
- end
- }
- end
-
- def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
- begin
- port = random(1024..65535)
- udpsock.bind(bind_host, port)
- rescue Errno::EADDRINUSE, # POSIX
- Errno::EACCES, # SunOS: See PRIV_SYS_NFS in privileges(5)
- Errno::EPERM # FreeBSD: security.mac.portacl.port_high is configurable. See mac_portacl(4).
- retry
- end
- end
-
- class Requester # :nodoc:
- def initialize
- @senders = {}
- @socks = nil
- end
-
- def request(sender, tout)
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- timelimit = start + tout
- begin
- sender.send
- rescue Errno::EHOSTUNREACH, # multi-homed IPv6 may generate this
- Errno::ENETUNREACH
- raise ResolvTimeout
- end
- while true
- before_select = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- timeout = timelimit - before_select
- if timeout <= 0
- raise ResolvTimeout
- end
- if @socks.size == 1
- select_result = @socks[0].wait_readable(timeout) ? [ @socks ] : nil
- else
- select_result = IO.select(@socks, nil, nil, timeout)
- end
- if !select_result
- after_select = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- next if after_select < timelimit
- raise ResolvTimeout
- end
- begin
- reply, from = recv_reply(select_result[0])
- rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD
- Errno::ECONNRESET # Windows
- # No name server running on the server?
- # Don't wait anymore.
- raise ResolvTimeout
- end
- begin
- msg = Message.decode(reply)
- rescue DecodeError
- next # broken DNS message ignored
- end
- if sender == sender_for(from, msg)
- break
- else
- # unexpected DNS message ignored
- end
- end
- return msg, sender.data
- end
-
- def sender_for(addr, msg)
- @senders[[addr,msg.id]]
- end
-
- def close
- socks = @socks
- @socks = nil
- socks&.each(&:close)
- end
-
- class Sender # :nodoc:
- def initialize(msg, data, sock)
- @msg = msg
- @data = data
- @sock = sock
- end
- end
-
- class UnconnectedUDP < Requester # :nodoc:
- def initialize(*nameserver_port)
- super()
- @nameserver_port = nameserver_port
- @initialized = false
- @mutex = Thread::Mutex.new
- end
-
- def lazy_initialize
- @mutex.synchronize {
- next if @initialized
- @initialized = true
- @socks_hash = {}
- @socks = []
- @nameserver_port.each {|host, port|
- if host.index(':')
- bind_host = "::"
- af = Socket::AF_INET6
- else
- bind_host = "0.0.0.0"
- af = Socket::AF_INET
- end
- next if @socks_hash[bind_host]
- begin
- sock = UDPSocket.new(af)
- rescue Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT
- next # The kernel doesn't support the address family.
- end
- @socks << sock
- @socks_hash[bind_host] = sock
- sock.do_not_reverse_lookup = true
- DNS.bind_random_port(sock, bind_host)
- }
- }
- self
- end
-
- def recv_reply(readable_socks)
- lazy_initialize
- reply, from = readable_socks[0].recvfrom(UDPSize)
- return reply, [from[3],from[1]]
- end
-
- def sender(msg, data, host, port=Port)
- host = Addrinfo.ip(host).ip_address
- lazy_initialize
- sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
- return nil if !sock
- service = [host, port]
- id = DNS.allocate_request_id(host, port)
- request = msg.encode
- request[0,2] = [id].pack('n')
- return @senders[[service, id]] =
- Sender.new(request, data, sock, host, port)
- end
-
- def close
- @mutex.synchronize {
- if @initialized
- super
- @senders.each_key {|service, id|
- DNS.free_request_id(service[0], service[1], id)
- }
- @initialized = false
- end
- }
- end
-
- class Sender < Requester::Sender # :nodoc:
- def initialize(msg, data, sock, host, port)
- super(msg, data, sock)
- @host = host
- @port = port
- end
- attr_reader :data
-
- def send
- raise "@sock is nil." if @sock.nil?
- @sock.send(@msg, 0, @host, @port)
- end
- end
- end
-
- class ConnectedUDP < Requester # :nodoc:
- def initialize(host, port=Port)
- super()
- @host = host
- @port = port
- @mutex = Thread::Mutex.new
- @initialized = false
- end
-
- def lazy_initialize
- @mutex.synchronize {
- next if @initialized
- @initialized = true
- is_ipv6 = @host.index(':')
- sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET)
- @socks = [sock]
- sock.do_not_reverse_lookup = true
- DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0")
- sock.connect(@host, @port)
- }
- self
- end
-
- def recv_reply(readable_socks)
- lazy_initialize
- reply = readable_socks[0].recv(UDPSize)
- return reply, nil
- end
-
- def sender(msg, data, host=@host, port=@port)
- lazy_initialize
- unless host == @host && port == @port
- raise RequestError.new("host/port don't match: #{host}:#{port}")
- end
- id = DNS.allocate_request_id(@host, @port)
- request = msg.encode
- request[0,2] = [id].pack('n')
- return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
- end
-
- def close
- @mutex.synchronize do
- if @initialized
- super
- @senders.each_key {|from, id|
- DNS.free_request_id(@host, @port, id)
- }
- @initialized = false
- end
- end
- end
-
- class Sender < Requester::Sender # :nodoc:
- def send
- raise "@sock is nil." if @sock.nil?
- @sock.send(@msg, 0)
- end
- attr_reader :data
- end
- end
-
- class MDNSOneShot < UnconnectedUDP # :nodoc:
- def sender(msg, data, host, port=Port)
- lazy_initialize
- id = DNS.allocate_request_id(host, port)
- request = msg.encode
- request[0,2] = [id].pack('n')
- sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
- return @senders[id] =
- UnconnectedUDP::Sender.new(request, data, sock, host, port)
- end
-
- def sender_for(addr, msg)
- lazy_initialize
- @senders[msg.id]
- end
- end
-
- class TCP < Requester # :nodoc:
- def initialize(host, port=Port)
- super()
- @host = host
- @port = port
- sock = TCPSocket.new(@host, @port)
- @socks = [sock]
- @senders = {}
- end
-
- def recv_reply(readable_socks)
- len = readable_socks[0].read(2).unpack('n')[0]
- reply = @socks[0].read(len)
- return reply, nil
- end
-
- def sender(msg, data, host=@host, port=@port)
- unless host == @host && port == @port
- raise RequestError.new("host/port don't match: #{host}:#{port}")
- end
- id = DNS.allocate_request_id(@host, @port)
- request = msg.encode
- request[0,2] = [request.length, id].pack('nn')
- return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
- end
-
- class Sender < Requester::Sender # :nodoc:
- def send
- @sock.print(@msg)
- @sock.flush
- end
- attr_reader :data
- end
-
- def close
- super
- @senders.each_key {|from,id|
- DNS.free_request_id(@host, @port, id)
- }
- end
- end
-
- ##
- # Indicates a problem with the DNS request.
-
- class RequestError < StandardError
- end
- end
-
- class Config # :nodoc:
- def initialize(config_info=nil)
- @mutex = Thread::Mutex.new
- @config_info = config_info
- @initialized = nil
- @timeouts = nil
- end
-
- def timeouts=(values)
- if values
- values = Array(values)
- values.each do |t|
- Numeric === t or raise ArgumentError, "#{t.inspect} is not numeric"
- t > 0.0 or raise ArgumentError, "timeout=#{t} must be positive"
- end
- @timeouts = values
- else
- @timeouts = nil
- end
- end
-
- def Config.parse_resolv_conf(filename)
- nameserver = []
- search = nil
- ndots = 1
- File.open(filename, 'rb') {|f|
- f.each {|line|
- line.sub!(/[#;].*/, '')
- keyword, *args = line.split(/\s+/)
- next unless keyword
- case keyword
- when 'nameserver'
- nameserver.concat(args)
- when 'domain'
- next if args.empty?
- search = [args[0]]
- when 'search'
- next if args.empty?
- search = args
- when 'options'
- args.each {|arg|
- case arg
- when /\Andots:(\d+)\z/
- ndots = $1.to_i
- end
- }
- end
- }
- }
- return { :nameserver => nameserver, :search => search, :ndots => ndots }
- end
-
- def Config.default_config_hash(filename="/etc/resolv.conf")
- if File.exist? filename
- config_hash = Config.parse_resolv_conf(filename)
- else
- if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
- require 'win32/resolv'
- search, nameserver = Win32::Resolv.get_resolv_info
- config_hash = {}
- config_hash[:nameserver] = nameserver if nameserver
- config_hash[:search] = [search].flatten if search
- end
- end
- config_hash || {}
- end
-
- def lazy_initialize
- @mutex.synchronize {
- unless @initialized
- @nameserver_port = []
- @use_ipv6 = nil
- @search = nil
- @ndots = 1
- case @config_info
- when nil
- config_hash = Config.default_config_hash
- when String
- config_hash = Config.parse_resolv_conf(@config_info)
- when Hash
- config_hash = @config_info.dup
- if String === config_hash[:nameserver]
- config_hash[:nameserver] = [config_hash[:nameserver]]
- end
- if String === config_hash[:search]
- config_hash[:search] = [config_hash[:search]]
- end
- else
- raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
- end
- if config_hash.include? :nameserver
- @nameserver_port = config_hash[:nameserver].map {|ns| [ns, Port] }
- end
- if config_hash.include? :nameserver_port
- @nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
- end
- if config_hash.include? :use_ipv6
- @use_ipv6 = config_hash[:use_ipv6]
- end
- @search = config_hash[:search] if config_hash.include? :search
- @ndots = config_hash[:ndots] if config_hash.include? :ndots
- @raise_timeout_errors = config_hash[:raise_timeout_errors]
-
- if @nameserver_port.empty?
- @nameserver_port << ['0.0.0.0', Port]
- end
- if @search
- @search = @search.map {|arg| Label.split(arg) }
- else
- hostname = Socket.gethostname
- if /\./ =~ hostname
- @search = [Label.split($')]
- else
- @search = [[]]
- end
- end
-
- if !@nameserver_port.kind_of?(Array) ||
- @nameserver_port.any? {|ns_port|
- !(Array === ns_port) ||
- ns_port.length != 2
- !(String === ns_port[0]) ||
- !(Integer === ns_port[1])
- }
- raise ArgumentError.new("invalid nameserver config: #{@nameserver_port.inspect}")
- end
-
- if !@search.kind_of?(Array) ||
- !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
- raise ArgumentError.new("invalid search config: #{@search.inspect}")
- end
-
- if !@ndots.kind_of?(Integer)
- raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
- end
-
- @initialized = true
- end
- }
- self
- end
-
- def single?
- lazy_initialize
- if @nameserver_port.length == 1
- return @nameserver_port[0]
- else
- return nil
- end
- end
-
- def nameserver_port
- @nameserver_port
- end
-
- def use_ipv6?
- @use_ipv6
- end
-
- def generate_candidates(name)
- candidates = nil
- name = Name.create(name)
- if name.absolute?
- candidates = [name]
- else
- if @ndots <= name.length - 1
- candidates = [Name.new(name.to_a)]
- else
- candidates = []
- end
- candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
- fname = Name.create("#{name}.")
- if !candidates.include?(fname)
- candidates << fname
- end
- end
- return candidates
- end
-
- InitialTimeout = 5
-
- def generate_timeouts
- ts = [InitialTimeout]
- ts << ts[-1] * 2 / @nameserver_port.length
- ts << ts[-1] * 2
- ts << ts[-1] * 2
- return ts
- end
-
- def resolv(name)
- candidates = generate_candidates(name)
- timeouts = @timeouts || generate_timeouts
- timeout_error = false
- begin
- candidates.each {|candidate|
- begin
- timeouts.each {|tout|
- @nameserver_port.each {|nameserver, port|
- begin
- yield candidate, tout, nameserver, port
- rescue ResolvTimeout
- end
- }
- }
- timeout_error = true
- raise ResolvError.new("DNS resolv timeout: #{name}")
- rescue NXDomain
- end
- }
- rescue ResolvError
- raise if @raise_timeout_errors && timeout_error
- end
- end
-
- ##
- # Indicates no such domain was found.
-
- class NXDomain < ResolvError
- end
-
- ##
- # Indicates some other unhandled resolver error was encountered.
-
- class OtherResolvError < ResolvError
- end
- end
-
- module OpCode # :nodoc:
- Query = 0
- IQuery = 1
- Status = 2
- Notify = 4
- Update = 5
- end
-
- module RCode # :nodoc:
- NoError = 0
- FormErr = 1
- ServFail = 2
- NXDomain = 3
- NotImp = 4
- Refused = 5
- YXDomain = 6
- YXRRSet = 7
- NXRRSet = 8
- NotAuth = 9
- NotZone = 10
- BADVERS = 16
- BADSIG = 16
- BADKEY = 17
- BADTIME = 18
- BADMODE = 19
- BADNAME = 20
- BADALG = 21
- end
-
- ##
- # Indicates that the DNS response was unable to be decoded.
-
- class DecodeError < StandardError
- end
-
- ##
- # Indicates that the DNS request was unable to be encoded.
-
- class EncodeError < StandardError
- end
-
- module Label # :nodoc:
- def self.split(arg)
- labels = []
- arg.scan(/[^\.]+/) {labels << Str.new($&)}
- return labels
- end
-
- class Str # :nodoc:
- def initialize(string)
- @string = string
- # case insensivity of DNS labels doesn't apply non-ASCII characters. [RFC 4343]
- # This assumes @string is given in ASCII compatible encoding.
- @downcase = string.b.downcase
- end
- attr_reader :string, :downcase
-
- def to_s
- return @string
- end
-
- def inspect
- return "#<#{self.class} #{self}>"
- end
-
- def ==(other)
- return self.class == other.class && @downcase == other.downcase
- end
-
- def eql?(other)
- return self == other
- end
-
- def hash
- return @downcase.hash
- end
- end
- end
-
- ##
- # A representation of a DNS name.
-
- class Name
-
- ##
- # Creates a new DNS name from +arg+. +arg+ can be:
- #
- # Name:: returns +arg+.
- # String:: Creates a new Name.
-
- def self.create(arg)
- case arg
- when Name
- return arg
- when String
- return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
- else
- raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
- end
- end
-
- def initialize(labels, absolute=true) # :nodoc:
- labels = labels.map {|label|
- case label
- when String then Label::Str.new(label)
- when Label::Str then label
- else
- raise ArgumentError, "unexpected label: #{label.inspect}"
- end
- }
- @labels = labels
- @absolute = absolute
- end
-
- def inspect # :nodoc:
- "#<#{self.class}: #{self}#{@absolute ? '.' : ''}>"
- end
-
- ##
- # True if this name is absolute.
-
- def absolute?
- return @absolute
- end
-
- def ==(other) # :nodoc:
- return false unless Name === other
- return false unless @absolute == other.absolute?
- return @labels == other.to_a
- end
-
- alias eql? == # :nodoc:
-
- ##
- # Returns true if +other+ is a subdomain.
- #
- # Example:
- #
- # domain = Gem::Resolv::DNS::Name.create("y.z")
- # p Gem::Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true
- # p Gem::Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true
- # p Gem::Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false
- # p Gem::Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false
- # p Gem::Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false
- # p Gem::Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false
- #
-
- def subdomain_of?(other)
- raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other
- return false if @absolute != other.absolute?
- other_len = other.length
- return false if @labels.length <= other_len
- return @labels[-other_len, other_len] == other.to_a
- end
-
- def hash # :nodoc:
- return @labels.hash ^ @absolute.hash
- end
-
- def to_a # :nodoc:
- return @labels
- end
-
- def length # :nodoc:
- return @labels.length
- end
-
- def [](i) # :nodoc:
- return @labels[i]
- end
-
- ##
- # returns the domain name as a string.
- #
- # The domain name doesn't have a trailing dot even if the name object is
- # absolute.
- #
- # Example:
- #
- # p Gem::Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z"
- # p Gem::Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z"
-
- def to_s
- return @labels.join('.')
- end
- end
-
- class Message # :nodoc:
- @@identifier = -1
-
- def initialize(id = (@@identifier += 1) & 0xffff)
- @id = id
- @qr = 0
- @opcode = 0
- @aa = 0
- @tc = 0
- @rd = 0 # recursion desired
- @ra = 0 # recursion available
- @rcode = 0
- @question = []
- @answer = []
- @authority = []
- @additional = []
- end
-
- attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode
- attr_reader :question, :answer, :authority, :additional
-
- def ==(other)
- return @id == other.id &&
- @qr == other.qr &&
- @opcode == other.opcode &&
- @aa == other.aa &&
- @tc == other.tc &&
- @rd == other.rd &&
- @ra == other.ra &&
- @rcode == other.rcode &&
- @question == other.question &&
- @answer == other.answer &&
- @authority == other.authority &&
- @additional == other.additional
- end
-
- def add_question(name, typeclass)
- @question << [Name.create(name), typeclass]
- end
-
- def each_question
- @question.each {|name, typeclass|
- yield name, typeclass
- }
- end
-
- def add_answer(name, ttl, data)
- @answer << [Name.create(name), ttl, data]
- end
-
- def each_answer
- @answer.each {|name, ttl, data|
- yield name, ttl, data
- }
- end
-
- def add_authority(name, ttl, data)
- @authority << [Name.create(name), ttl, data]
- end
-
- def each_authority
- @authority.each {|name, ttl, data|
- yield name, ttl, data
- }
- end
-
- def add_additional(name, ttl, data)
- @additional << [Name.create(name), ttl, data]
- end
-
- def each_additional
- @additional.each {|name, ttl, data|
- yield name, ttl, data
- }
- end
-
- def each_resource
- each_answer {|name, ttl, data| yield name, ttl, data}
- each_authority {|name, ttl, data| yield name, ttl, data}
- each_additional {|name, ttl, data| yield name, ttl, data}
- end
-
- def encode
- return MessageEncoder.new {|msg|
- msg.put_pack('nnnnnn',
- @id,
- (@qr & 1) << 15 |
- (@opcode & 15) << 11 |
- (@aa & 1) << 10 |
- (@tc & 1) << 9 |
- (@rd & 1) << 8 |
- (@ra & 1) << 7 |
- (@rcode & 15),
- @question.length,
- @answer.length,
- @authority.length,
- @additional.length)
- @question.each {|q|
- name, typeclass = q
- msg.put_name(name)
- msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue)
- }
- [@answer, @authority, @additional].each {|rr|
- rr.each {|r|
- name, ttl, data = r
- msg.put_name(name)
- msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl)
- msg.put_length16 {data.encode_rdata(msg)}
- }
- }
- }.to_s
- end
-
- class MessageEncoder # :nodoc:
- def initialize
- @data = ''.dup
- @names = {}
- yield self
- end
-
- def to_s
- return @data
- end
-
- def put_bytes(d)
- @data << d
- end
-
- def put_pack(template, *d)
- @data << d.pack(template)
- end
-
- def put_length16
- length_index = @data.length
- @data << "\0\0"
- data_start = @data.length
- yield
- data_end = @data.length
- @data[length_index, 2] = [data_end - data_start].pack("n")
- end
-
- def put_string(d)
- self.put_pack("C", d.length)
- @data << d
- end
-
- def put_string_list(ds)
- ds.each {|d|
- self.put_string(d)
- }
- end
-
- def put_name(d, compress: true)
- put_labels(d.to_a, compress: compress)
- end
-
- def put_labels(d, compress: true)
- d.each_index {|i|
- domain = d[i..-1]
- if compress && idx = @names[domain]
- self.put_pack("n", 0xc000 | idx)
- return
- else
- if @data.length < 0x4000
- @names[domain] = @data.length
- end
- self.put_label(d[i])
- end
- }
- @data << "\0"
- end
-
- def put_label(d)
- self.put_string(d.to_s)
- end
- end
-
- def Message.decode(m)
- o = Message.new(0)
- MessageDecoder.new(m) {|msg|
- id, flag, qdcount, ancount, nscount, arcount =
- msg.get_unpack('nnnnnn')
- o.id = id
- o.tc = (flag >> 9) & 1
- o.rcode = flag & 15
- return o unless o.tc.zero?
-
- o.qr = (flag >> 15) & 1
- o.opcode = (flag >> 11) & 15
- o.aa = (flag >> 10) & 1
- o.rd = (flag >> 8) & 1
- o.ra = (flag >> 7) & 1
- (1..qdcount).each {
- name, typeclass = msg.get_question
- o.add_question(name, typeclass)
- }
- (1..ancount).each {
- name, ttl, data = msg.get_rr
- o.add_answer(name, ttl, data)
- }
- (1..nscount).each {
- name, ttl, data = msg.get_rr
- o.add_authority(name, ttl, data)
- }
- (1..arcount).each {
- name, ttl, data = msg.get_rr
- o.add_additional(name, ttl, data)
- }
- }
- return o
- end
-
- class MessageDecoder # :nodoc:
- def initialize(data)
- @data = data
- @index = 0
- @limit = data.bytesize
- yield self
- end
-
- def inspect
- "\#<#{self.class}: #{@data.byteslice(0, @index).inspect} #{@data.byteslice(@index..-1).inspect}>"
- end
-
- def get_length16
- len, = self.get_unpack('n')
- save_limit = @limit
- @limit = @index + len
- d = yield(len)
- if @index < @limit
- raise DecodeError.new("junk exists")
- elsif @limit < @index
- raise DecodeError.new("limit exceeded")
- end
- @limit = save_limit
- return d
- end
-
- def get_bytes(len = @limit - @index)
- raise DecodeError.new("limit exceeded") if @limit < @index + len
- d = @data.byteslice(@index, len)
- @index += len
- return d
- end
-
- def get_unpack(template)
- len = 0
- template.each_byte {|byte|
- byte = "%c" % byte
- case byte
- when ?c, ?C
- len += 1
- when ?n
- len += 2
- when ?N
- len += 4
- else
- raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'")
- end
- }
- raise DecodeError.new("limit exceeded") if @limit < @index + len
- arr = @data.unpack("@#{@index}#{template}")
- @index += len
- return arr
- end
-
- def get_string
- raise DecodeError.new("limit exceeded") if @limit <= @index
- len = @data.getbyte(@index)
- raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len
- d = @data.byteslice(@index + 1, len)
- @index += 1 + len
- return d
- end
-
- def get_string_list
- strings = []
- while @index < @limit
- strings << self.get_string
- end
- strings
- end
-
- def get_list
- [].tap do |values|
- while @index < @limit
- values << yield
- end
- end
- end
-
- def get_name
- return Name.new(self.get_labels)
- end
-
- def get_labels
- prev_index = @index
- save_index = nil
- d = []
- while true
- raise DecodeError.new("limit exceeded") if @limit <= @index
- case @data.getbyte(@index)
- when 0
- @index += 1
- if save_index
- @index = save_index
- end
- return d
- when 192..255
- idx = self.get_unpack('n')[0] & 0x3fff
- if prev_index <= idx
- raise DecodeError.new("non-backward name pointer")
- end
- prev_index = idx
- if !save_index
- save_index = @index
- end
- @index = idx
- else
- d << self.get_label
- end
- end
- end
-
- def get_label
- return Label::Str.new(self.get_string)
- end
-
- def get_question
- name = self.get_name
- type, klass = self.get_unpack("nn")
- return name, Resource.get_class(type, klass)
- end
-
- def get_rr
- name = self.get_name
- type, klass, ttl = self.get_unpack('nnN')
- typeclass = Resource.get_class(type, klass)
- res = self.get_length16 do
- begin
- typeclass.decode_rdata self
- rescue => e
- raise DecodeError, e.message, e.backtrace
- end
- end
- res.instance_variable_set :@ttl, ttl
- return name, ttl, res
- end
- end
- end
-
- ##
- # SvcParams for service binding RRs. [RFC9460]
-
- class SvcParams
- include Enumerable
-
- ##
- # Create a list of SvcParams with the given initial content.
- #
- # +params+ has to be an enumerable of +SvcParam+s.
- # If its content has +SvcParam+s with the duplicate key,
- # the one appears last takes precedence.
-
- def initialize(params = [])
- @params = {}
-
- params.each do |param|
- add param
- end
- end
-
- ##
- # Get SvcParam for the given +key+ in this list.
-
- def [](key)
- @params[canonical_key(key)]
- end
-
- ##
- # Get the number of SvcParams in this list.
-
- def count
- @params.count
- end
-
- ##
- # Get whether this list is empty.
-
- def empty?
- @params.empty?
- end
-
- ##
- # Add the SvcParam +param+ to this list, overwriting the existing one with the same key.
-
- def add(param)
- @params[param.class.key_number] = param
- end
-
- ##
- # Remove the +SvcParam+ with the given +key+ and return it.
-
- def delete(key)
- @params.delete(canonical_key(key))
- end
-
- ##
- # Enumerate the +SvcParam+s in this list.
-
- def each(&block)
- return enum_for(:each) unless block
- @params.each_value(&block)
- end
-
- def encode(msg) # :nodoc:
- @params.keys.sort.each do |key|
- msg.put_pack('n', key)
- msg.put_length16 do
- @params.fetch(key).encode(msg)
- end
- end
- end
-
- def self.decode(msg) # :nodoc:
- params = msg.get_list do
- key, = msg.get_unpack('n')
- msg.get_length16 do
- SvcParam::ClassHash[key].decode(msg)
- end
- end
-
- return self.new(params)
- end
-
- private
-
- def canonical_key(key) # :nodoc:
- case key
- when Integer
- key
- when /\Akey(\d+)\z/
- Integer($1)
- when Symbol
- SvcParam::ClassHash[key].key_number
- else
- raise TypeError, 'key must be either String or Symbol'
- end
- end
- end
-
-
- ##
- # Base class for SvcParam. [RFC9460]
-
- class SvcParam
-
- ##
- # Get the presentation name of the SvcParamKey.
-
- def self.key_name
- const_get(:KeyName)
- end
-
- ##
- # Get the registered number of the SvcParamKey.
-
- def self.key_number
- const_get(:KeyNumber)
- end
-
- ClassHash = Hash.new do |h, key| # :nodoc:
- case key
- when Integer
- Generic.create(key)
- when /\Akey(?<key>\d+)\z/
- Generic.create(key.to_int)
- when Symbol
- raise KeyError, "unknown key #{key}"
- else
- raise TypeError, 'key must be either String or Symbol'
- end
- end
-
- ##
- # Generic SvcParam abstract class.
-
- class Generic < SvcParam
-
- ##
- # SvcParamValue in wire-format byte string.
-
- attr_reader :value
-
- ##
- # Create generic SvcParam
-
- def initialize(value)
- @value = value
- end
-
- def encode(msg) # :nodoc:
- msg.put_bytes(@value)
- end
-
- def self.decode(msg) # :nodoc:
- return self.new(msg.get_bytes)
- end
-
- def self.create(key_number)
- c = Class.new(Generic)
- key_name = :"key#{key_number}"
- c.const_set(:KeyName, key_name)
- c.const_set(:KeyNumber, key_number)
- self.const_set(:"Key#{key_number}", c)
- ClassHash[key_name] = ClassHash[key_number] = c
- return c
- end
- end
-
- ##
- # "mandatory" SvcParam -- Mandatory keys in service binding RR
-
- class Mandatory < SvcParam
- KeyName = :mandatory
- KeyNumber = 0
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Mandatory keys.
-
- attr_reader :keys
-
- ##
- # Initialize "mandatory" ScvParam.
-
- def initialize(keys)
- @keys = keys.map(&:to_int)
- end
-
- def encode(msg) # :nodoc:
- @keys.sort.each do |key|
- msg.put_pack('n', key)
- end
- end
-
- def self.decode(msg) # :nodoc:
- keys = msg.get_list { msg.get_unpack('n')[0] }
- return self.new(keys)
- end
- end
-
- ##
- # "alpn" SvcParam -- Additional supported protocols
-
- class ALPN < SvcParam
- KeyName = :alpn
- KeyNumber = 1
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Supported protocol IDs.
-
- attr_reader :protocol_ids
-
- ##
- # Initialize "alpn" ScvParam.
-
- def initialize(protocol_ids)
- @protocol_ids = protocol_ids.map(&:to_str)
- end
-
- def encode(msg) # :nodoc:
- msg.put_string_list(@protocol_ids)
- end
-
- def self.decode(msg) # :nodoc:
- return self.new(msg.get_string_list)
- end
- end
-
- ##
- # "no-default-alpn" SvcParam -- No support for default protocol
-
- class NoDefaultALPN < SvcParam
- KeyName = :'no-default-alpn'
- KeyNumber = 2
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- def encode(msg) # :nodoc:
- # no payload
- end
-
- def self.decode(msg) # :nodoc:
- return self.new
- end
- end
-
- ##
- # "port" SvcParam -- Port for alternative endpoint
-
- class Port < SvcParam
- KeyName = :port
- KeyNumber = 3
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Port number.
-
- attr_reader :port
-
- ##
- # Initialize "port" ScvParam.
-
- def initialize(port)
- @port = port.to_int
- end
-
- def encode(msg) # :nodoc:
- msg.put_pack('n', @port)
- end
-
- def self.decode(msg) # :nodoc:
- port, = msg.get_unpack('n')
- return self.new(port)
- end
- end
-
- ##
- # "ipv4hint" SvcParam -- IPv4 address hints
-
- class IPv4Hint < SvcParam
- KeyName = :ipv4hint
- KeyNumber = 4
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Set of IPv4 addresses.
-
- attr_reader :addresses
-
- ##
- # Initialize "ipv4hint" ScvParam.
-
- def initialize(addresses)
- @addresses = addresses.map {|address| IPv4.create(address) }
- end
-
- def encode(msg) # :nodoc:
- @addresses.each do |address|
- msg.put_bytes(address.address)
- end
- end
-
- def self.decode(msg) # :nodoc:
- addresses = msg.get_list { IPv4.new(msg.get_bytes(4)) }
- return self.new(addresses)
- end
- end
-
- ##
- # "ipv6hint" SvcParam -- IPv6 address hints
-
- class IPv6Hint < SvcParam
- KeyName = :ipv6hint
- KeyNumber = 6
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Set of IPv6 addresses.
-
- attr_reader :addresses
-
- ##
- # Initialize "ipv6hint" ScvParam.
-
- def initialize(addresses)
- @addresses = addresses.map {|address| IPv6.create(address) }
- end
-
- def encode(msg) # :nodoc:
- @addresses.each do |address|
- msg.put_bytes(address.address)
- end
- end
-
- def self.decode(msg) # :nodoc:
- addresses = msg.get_list { IPv6.new(msg.get_bytes(16)) }
- return self.new(addresses)
- end
- end
-
- ##
- # "dohpath" SvcParam -- DNS over HTTPS path template [RFC9461]
-
- class DoHPath < SvcParam
- KeyName = :dohpath
- KeyNumber = 7
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # URI template for DoH queries.
-
- attr_reader :template
-
- ##
- # Initialize "dohpath" ScvParam.
-
- def initialize(template)
- @template = template.encode('utf-8')
- end
-
- def encode(msg) # :nodoc:
- msg.put_bytes(@template)
- end
-
- def self.decode(msg) # :nodoc:
- template = msg.get_bytes.force_encoding('utf-8')
- return self.new(template)
- end
- end
- end
-
- ##
- # A DNS query abstract class.
-
- class Query
- def encode_rdata(msg) # :nodoc:
- raise EncodeError.new("#{self.class} is query.")
- end
-
- def self.decode_rdata(msg) # :nodoc:
- raise DecodeError.new("#{self.class} is query.")
- end
- end
-
- ##
- # A DNS resource abstract class.
-
- class Resource < Query
-
- ##
- # Remaining Time To Live for this Resource.
-
- attr_reader :ttl
-
- ClassHash = {} # :nodoc:
-
- def encode_rdata(msg) # :nodoc:
- raise NotImplementedError.new
- end
-
- def self.decode_rdata(msg) # :nodoc:
- raise NotImplementedError.new
- end
-
- def ==(other) # :nodoc:
- return false unless self.class == other.class
- s_ivars = self.instance_variables
- s_ivars.sort!
- s_ivars.delete :@ttl
- o_ivars = other.instance_variables
- o_ivars.sort!
- o_ivars.delete :@ttl
- return s_ivars == o_ivars &&
- s_ivars.collect {|name| self.instance_variable_get name} ==
- o_ivars.collect {|name| other.instance_variable_get name}
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- h = 0
- vars = self.instance_variables
- vars.delete :@ttl
- vars.each {|name|
- h ^= self.instance_variable_get(name).hash
- }
- return h
- end
-
- def self.get_class(type_value, class_value) # :nodoc:
- return ClassHash[[type_value, class_value]] ||
- Generic.create(type_value, class_value)
- end
-
- ##
- # A generic resource abstract class.
-
- class Generic < Resource
-
- ##
- # Creates a new generic resource.
-
- def initialize(data)
- @data = data
- end
-
- ##
- # Data for this generic resource.
-
- attr_reader :data
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(data)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- return self.new(msg.get_bytes)
- end
-
- def self.create(type_value, class_value) # :nodoc:
- c = Class.new(Generic)
- c.const_set(:TypeValue, type_value)
- c.const_set(:ClassValue, class_value)
- Generic.const_set("Type#{type_value}_Class#{class_value}", c)
- ClassHash[[type_value, class_value]] = c
- return c
- end
- end
-
- ##
- # Domain Name resource abstract class.
-
- class DomainName < Resource
-
- ##
- # Creates a new DomainName from +name+.
-
- def initialize(name)
- @name = name
- end
-
- ##
- # The name of this DomainName.
-
- attr_reader :name
-
- def encode_rdata(msg) # :nodoc:
- msg.put_name(@name)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- return self.new(msg.get_name)
- end
- end
-
- # Standard (class generic) RRs
-
- ClassValue = nil # :nodoc:
-
- ##
- # An authoritative name server.
-
- class NS < DomainName
- TypeValue = 2 # :nodoc:
- end
-
- ##
- # The canonical name for an alias.
-
- class CNAME < DomainName
- TypeValue = 5 # :nodoc:
- end
-
- ##
- # Start Of Authority resource.
-
- class SOA < Resource
-
- TypeValue = 6 # :nodoc:
-
- ##
- # Creates a new SOA record. See the attr documentation for the
- # details of each argument.
-
- def initialize(mname, rname, serial, refresh, retry_, expire, minimum)
- @mname = mname
- @rname = rname
- @serial = serial
- @refresh = refresh
- @retry = retry_
- @expire = expire
- @minimum = minimum
- end
-
- ##
- # Name of the host where the master zone file for this zone resides.
-
- attr_reader :mname
-
- ##
- # The person responsible for this domain name.
-
- attr_reader :rname
-
- ##
- # The version number of the zone file.
-
- attr_reader :serial
-
- ##
- # How often, in seconds, a secondary name server is to check for
- # updates from the primary name server.
-
- attr_reader :refresh
-
- ##
- # How often, in seconds, a secondary name server is to retry after a
- # failure to check for a refresh.
-
- attr_reader :retry
-
- ##
- # Time in seconds that a secondary name server is to use the data
- # before refreshing from the primary name server.
-
- attr_reader :expire
-
- ##
- # The minimum number of seconds to be used for TTL values in RRs.
-
- attr_reader :minimum
-
- def encode_rdata(msg) # :nodoc:
- msg.put_name(@mname)
- msg.put_name(@rname)
- msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- mname = msg.get_name
- rname = msg.get_name
- serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN')
- return self.new(
- mname, rname, serial, refresh, retry_, expire, minimum)
- end
- end
-
- ##
- # A Pointer to another DNS name.
-
- class PTR < DomainName
- TypeValue = 12 # :nodoc:
- end
-
- ##
- # Host Information resource.
-
- class HINFO < Resource
-
- TypeValue = 13 # :nodoc:
-
- ##
- # Creates a new HINFO running +os+ on +cpu+.
-
- def initialize(cpu, os)
- @cpu = cpu
- @os = os
- end
-
- ##
- # CPU architecture for this resource.
-
- attr_reader :cpu
-
- ##
- # Operating system for this resource.
-
- attr_reader :os
-
- def encode_rdata(msg) # :nodoc:
- msg.put_string(@cpu)
- msg.put_string(@os)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- cpu = msg.get_string
- os = msg.get_string
- return self.new(cpu, os)
- end
- end
-
- ##
- # Mailing list or mailbox information.
-
- class MINFO < Resource
-
- TypeValue = 14 # :nodoc:
-
- def initialize(rmailbx, emailbx)
- @rmailbx = rmailbx
- @emailbx = emailbx
- end
-
- ##
- # Domain name responsible for this mail list or mailbox.
-
- attr_reader :rmailbx
-
- ##
- # Mailbox to use for error messages related to the mail list or mailbox.
-
- attr_reader :emailbx
-
- def encode_rdata(msg) # :nodoc:
- msg.put_name(@rmailbx)
- msg.put_name(@emailbx)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- rmailbx = msg.get_string
- emailbx = msg.get_string
- return self.new(rmailbx, emailbx)
- end
- end
-
- ##
- # Mail Exchanger resource.
-
- class MX < Resource
-
- TypeValue= 15 # :nodoc:
-
- ##
- # Creates a new MX record with +preference+, accepting mail at
- # +exchange+.
-
- def initialize(preference, exchange)
- @preference = preference
- @exchange = exchange
- end
-
- ##
- # The preference for this MX.
-
- attr_reader :preference
-
- ##
- # The host of this MX.
-
- attr_reader :exchange
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack('n', @preference)
- msg.put_name(@exchange)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- preference, = msg.get_unpack('n')
- exchange = msg.get_name
- return self.new(preference, exchange)
- end
- end
-
- ##
- # Unstructured text resource.
-
- class TXT < Resource
-
- TypeValue = 16 # :nodoc:
-
- def initialize(first_string, *rest_strings)
- @strings = [first_string, *rest_strings]
- end
-
- ##
- # Returns an Array of Strings for this TXT record.
-
- attr_reader :strings
-
- ##
- # Returns the concatenated string from +strings+.
-
- def data
- @strings.join("")
- end
-
- def encode_rdata(msg) # :nodoc:
- msg.put_string_list(@strings)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- strings = msg.get_string_list
- return self.new(*strings)
- end
- end
-
- ##
- # Location resource
-
- class LOC < Resource
-
- TypeValue = 29 # :nodoc:
-
- def initialize(version, ssize, hprecision, vprecision, latitude, longitude, altitude)
- @version = version
- @ssize = Gem::Resolv::LOC::Size.create(ssize)
- @hprecision = Gem::Resolv::LOC::Size.create(hprecision)
- @vprecision = Gem::Resolv::LOC::Size.create(vprecision)
- @latitude = Gem::Resolv::LOC::Coord.create(latitude)
- @longitude = Gem::Resolv::LOC::Coord.create(longitude)
- @altitude = Gem::Resolv::LOC::Alt.create(altitude)
- end
-
- ##
- # Returns the version value for this LOC record which should always be 00
-
- attr_reader :version
-
- ##
- # The spherical size of this LOC
- # in meters using scientific notation as 2 integers of XeY
-
- attr_reader :ssize
-
- ##
- # The horizontal precision using ssize type values
- # in meters using scientific notation as 2 integers of XeY
- # for precision use value/2 e.g. 2m = +/-1m
-
- attr_reader :hprecision
-
- ##
- # The vertical precision using ssize type values
- # in meters using scientific notation as 2 integers of XeY
- # for precision use value/2 e.g. 2m = +/-1m
-
- attr_reader :vprecision
-
- ##
- # The latitude for this LOC where 2**31 is the equator
- # in thousandths of an arc second as an unsigned 32bit integer
-
- attr_reader :latitude
-
- ##
- # The longitude for this LOC where 2**31 is the prime meridian
- # in thousandths of an arc second as an unsigned 32bit integer
-
- attr_reader :longitude
-
- ##
- # The altitude of the LOC above a reference sphere whose surface sits 100km below the WGS84 spheroid
- # in centimeters as an unsigned 32bit integer
-
- attr_reader :altitude
-
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(@version)
- msg.put_bytes(@ssize.scalar)
- msg.put_bytes(@hprecision.scalar)
- msg.put_bytes(@vprecision.scalar)
- msg.put_bytes(@latitude.coordinates)
- msg.put_bytes(@longitude.coordinates)
- msg.put_bytes(@altitude.altitude)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- version = msg.get_bytes(1)
- ssize = msg.get_bytes(1)
- hprecision = msg.get_bytes(1)
- vprecision = msg.get_bytes(1)
- latitude = msg.get_bytes(4)
- longitude = msg.get_bytes(4)
- altitude = msg.get_bytes(4)
- return self.new(
- version,
- Gem::Resolv::LOC::Size.new(ssize),
- Gem::Resolv::LOC::Size.new(hprecision),
- Gem::Resolv::LOC::Size.new(vprecision),
- Gem::Resolv::LOC::Coord.new(latitude,"lat"),
- Gem::Resolv::LOC::Coord.new(longitude,"lon"),
- Gem::Resolv::LOC::Alt.new(altitude)
- )
- end
- end
-
- ##
- # A Query type requesting any RR.
-
- class ANY < Query
- TypeValue = 255 # :nodoc:
- end
-
- ##
- # CAA resource record defined in RFC 8659
- #
- # These records identify certificate authority allowed to issue
- # certificates for the given domain.
-
- class CAA < Resource
- TypeValue = 257
-
- ##
- # Creates a new CAA for +flags+, +tag+ and +value+.
-
- def initialize(flags, tag, value)
- unless (0..255) === flags
- raise ArgumentError.new('flags must be an Integer between 0 and 255')
- end
- unless (1..15) === tag.bytesize
- raise ArgumentError.new('length of tag must be between 1 and 15')
- end
-
- @flags = flags
- @tag = tag
- @value = value
- end
-
- ##
- # Flags for this proprty:
- # - Bit 0 : 0 = not critical, 1 = critical
-
- attr_reader :flags
-
- ##
- # Property tag ("issue", "issuewild", "iodef"...).
-
- attr_reader :tag
-
- ##
- # Property value.
-
- attr_reader :value
-
- ##
- # Whether the critical flag is set on this property.
-
- def critical?
- flags & 0x80 != 0
- end
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack('C', @flags)
- msg.put_string(@tag)
- msg.put_bytes(@value)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- flags, = msg.get_unpack('C')
- tag = msg.get_string
- value = msg.get_bytes
- self.new flags, tag, value
- end
- end
-
- ClassInsensitiveTypes = [ # :nodoc:
- NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY, CAA
- ]
-
- ##
- # module IN contains ARPA Internet specific RRs.
-
- module IN
-
- ClassValue = 1 # :nodoc:
-
- ClassInsensitiveTypes.each {|s|
- c = Class.new(s)
- c.const_set(:TypeValue, s::TypeValue)
- c.const_set(:ClassValue, ClassValue)
- ClassHash[[s::TypeValue, ClassValue]] = c
- self.const_set(s.name.sub(/.*::/, ''), c)
- }
-
- ##
- # IPv4 Address resource
-
- class A < Resource
- TypeValue = 1
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
-
- ##
- # Creates a new A for +address+.
-
- def initialize(address)
- @address = IPv4.create(address)
- end
-
- ##
- # The Gem::Resolv::IPv4 address for this A.
-
- attr_reader :address
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(@address.address)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- return self.new(IPv4.new(msg.get_bytes(4)))
- end
- end
-
- ##
- # Well Known Service resource.
-
- class WKS < Resource
- TypeValue = 11
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
-
- def initialize(address, protocol, bitmap)
- @address = IPv4.create(address)
- @protocol = protocol
- @bitmap = bitmap
- end
-
- ##
- # The host these services run on.
-
- attr_reader :address
-
- ##
- # IP protocol number for these services.
-
- attr_reader :protocol
-
- ##
- # A bit map of enabled services on this host.
- #
- # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP
- # service (port 25). If this bit is set, then an SMTP server should
- # be listening on TCP port 25; if zero, SMTP service is not
- # supported.
-
- attr_reader :bitmap
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(@address.address)
- msg.put_pack("n", @protocol)
- msg.put_bytes(@bitmap)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- address = IPv4.new(msg.get_bytes(4))
- protocol, = msg.get_unpack("n")
- bitmap = msg.get_bytes
- return self.new(address, protocol, bitmap)
- end
- end
-
- ##
- # An IPv6 address record.
-
- class AAAA < Resource
- TypeValue = 28
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
-
- ##
- # Creates a new AAAA for +address+.
-
- def initialize(address)
- @address = IPv6.create(address)
- end
-
- ##
- # The Gem::Resolv::IPv6 address for this AAAA.
-
- attr_reader :address
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(@address.address)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- return self.new(IPv6.new(msg.get_bytes(16)))
- end
- end
-
- ##
- # SRV resource record defined in RFC 2782
- #
- # These records identify the hostname and port that a service is
- # available at.
-
- class SRV < Resource
- TypeValue = 33
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
-
- # Create a SRV resource record.
- #
- # See the documentation for #priority, #weight, #port and #target
- # for +priority+, +weight+, +port and +target+ respectively.
-
- def initialize(priority, weight, port, target)
- @priority = priority.to_int
- @weight = weight.to_int
- @port = port.to_int
- @target = Name.create(target)
- end
-
- # The priority of this target host.
- #
- # A client MUST attempt to contact the target host with the
- # lowest-numbered priority it can reach; target hosts with the same
- # priority SHOULD be tried in an order defined by the weight field.
- # The range is 0-65535. Note that it is not widely implemented and
- # should be set to zero.
-
- attr_reader :priority
-
- # A server selection mechanism.
- #
- # The weight field specifies a relative weight for entries with the
- # same priority. Larger weights SHOULD be given a proportionately
- # higher probability of being selected. The range of this number is
- # 0-65535. Domain administrators SHOULD use Weight 0 when there
- # isn't any server selection to do, to make the RR easier to read
- # for humans (less noisy). Note that it is not widely implemented
- # and should be set to zero.
-
- attr_reader :weight
-
- # The port on this target host of this service.
- #
- # The range is 0-65535.
-
- attr_reader :port
-
- # The domain name of the target host.
- #
- # A target of "." means that the service is decidedly not available
- # at this domain.
-
- attr_reader :target
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack("n", @priority)
- msg.put_pack("n", @weight)
- msg.put_pack("n", @port)
- msg.put_name(@target, compress: false)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- priority, = msg.get_unpack("n")
- weight, = msg.get_unpack("n")
- port, = msg.get_unpack("n")
- target = msg.get_name
- return self.new(priority, weight, port, target)
- end
- end
-
- ##
- # Common implementation for SVCB-compatible resource records.
-
- class ServiceBinding
-
- ##
- # Create a service binding resource record.
-
- def initialize(priority, target, params = [])
- @priority = priority.to_int
- @target = Name.create(target)
- @params = SvcParams.new(params)
- end
-
- ##
- # The priority of this target host.
- #
- # The range is 0-65535.
- # If set to 0, this RR is in AliasMode. Otherwise, it is in ServiceMode.
-
- attr_reader :priority
-
- ##
- # The domain name of the target host.
-
- attr_reader :target
-
- ##
- # The service parameters for the target host.
-
- attr_reader :params
-
- ##
- # Whether this RR is in AliasMode.
-
- def alias_mode?
- self.priority == 0
- end
-
- ##
- # Whether this RR is in ServiceMode.
-
- def service_mode?
- !alias_mode?
- end
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack("n", @priority)
- msg.put_name(@target, compress: false)
- @params.encode(msg)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- priority, = msg.get_unpack("n")
- target = msg.get_name
- params = SvcParams.decode(msg)
- return self.new(priority, target, params)
- end
- end
-
- ##
- # SVCB resource record [RFC9460]
-
- class SVCB < ServiceBinding
- TypeValue = 64
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
- end
-
- ##
- # HTTPS resource record [RFC9460]
-
- class HTTPS < ServiceBinding
- TypeValue = 65
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
- end
- end
- end
- end
-
- ##
- # A Gem::Resolv::DNS IPv4 address.
-
- class IPv4
-
- ##
- # Regular expression IPv4 addresses must match.
-
- Regex256 = /0
- |1(?:[0-9][0-9]?)?
- |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
- |[3-9][0-9]?/x
- Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
-
- def self.create(arg)
- case arg
- when IPv4
- return arg
- when Regex
- if (0..255) === (a = $1.to_i) &&
- (0..255) === (b = $2.to_i) &&
- (0..255) === (c = $3.to_i) &&
- (0..255) === (d = $4.to_i)
- return self.new([a, b, c, d].pack("CCCC"))
- else
- raise ArgumentError.new("IPv4 address with invalid value: " + arg)
- end
- else
- raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}")
- end
- end
-
- def initialize(address) # :nodoc:
- unless address.kind_of?(String)
- raise ArgumentError, 'IPv4 address must be a string'
- end
- unless address.length == 4
- raise ArgumentError, "IPv4 address expects 4 bytes but #{address.length} bytes"
- end
- @address = address
- end
-
- ##
- # A String representation of this IPv4 address.
-
- ##
- # The raw IPv4 address as a String.
-
- attr_reader :address
-
- def to_s # :nodoc:
- return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC"))
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- ##
- # Turns this IPv4 address into a Gem::Resolv::DNS::Name.
-
- def to_name
- return DNS::Name.create(
- '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse)
- end
-
- def ==(other) # :nodoc:
- return @address == other.address
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @address.hash
- end
- end
-
- ##
- # A Gem::Resolv::DNS IPv6 address.
-
- class IPv6
-
- ##
- # IPv6 address format a:b:c:d:e:f:g:h
- Regex_8Hex = /\A
- (?:[0-9A-Fa-f]{1,4}:){7}
- [0-9A-Fa-f]{1,4}
- \z/x
-
- ##
- # Compressed IPv6 address format a::b
-
- Regex_CompressedHex = /\A
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
- \z/x
-
- ##
- # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z
-
- Regex_6Hex4Dec = /\A
- ((?:[0-9A-Fa-f]{1,4}:){6,6})
- (\d+)\.(\d+)\.(\d+)\.(\d+)
- \z/x
-
- ##
- # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z
-
- Regex_CompressedHex4Dec = /\A
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
- ((?:[0-9A-Fa-f]{1,4}:)*)
- (\d+)\.(\d+)\.(\d+)\.(\d+)
- \z/x
-
- ##
- # IPv6 link local address format fe80:b:c:d:e:f:g:h%em1
- Regex_8HexLinkLocal = /\A
- [Ff][Ee]80
- (?::[0-9A-Fa-f]{1,4}){7}
- %[-0-9A-Za-z._~]+
- \z/x
-
- ##
- # Compressed IPv6 link local address format fe80::b%em1
-
- Regex_CompressedHexLinkLocal = /\A
- [Ff][Ee]80:
- (?:
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
- |
- :((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
- )?
- :[0-9A-Fa-f]{1,4}%[-0-9A-Za-z._~]+
- \z/x
-
- ##
- # A composite IPv6 address Regexp.
-
- Regex = /
- (?:#{Regex_8Hex}) |
- (?:#{Regex_CompressedHex}) |
- (?:#{Regex_6Hex4Dec}) |
- (?:#{Regex_CompressedHex4Dec}) |
- (?:#{Regex_8HexLinkLocal}) |
- (?:#{Regex_CompressedHexLinkLocal})
- /x
-
- ##
- # Creates a new IPv6 address from +arg+ which may be:
- #
- # IPv6:: returns +arg+.
- # String:: +arg+ must match one of the IPv6::Regex* constants
-
- def self.create(arg)
- case arg
- when IPv6
- return arg
- when String
- address = ''.b
- if Regex_8Hex =~ arg
- arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
- elsif Regex_CompressedHex =~ arg
- prefix = $1
- suffix = $2
- a1 = ''.b
- a2 = ''.b
- prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
- suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
- omitlen = 16 - a1.length - a2.length
- address << a1 << "\0" * omitlen << a2
- elsif Regex_6Hex4Dec =~ arg
- prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i
- if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
- prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
- address << [a, b, c, d].pack('CCCC')
- else
- raise ArgumentError.new("not numeric IPv6 address: " + arg)
- end
- elsif Regex_CompressedHex4Dec =~ arg
- prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i
- if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
- a1 = ''.b
- a2 = ''.b
- prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
- suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
- omitlen = 12 - a1.length - a2.length
- address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC')
- else
- raise ArgumentError.new("not numeric IPv6 address: " + arg)
- end
- else
- raise ArgumentError.new("not numeric IPv6 address: " + arg)
- end
- return IPv6.new(address)
- else
- raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}")
- end
- end
-
- def initialize(address) # :nodoc:
- unless address.kind_of?(String) && address.length == 16
- raise ArgumentError.new('IPv6 address must be 16 bytes')
- end
- @address = address
- end
-
- ##
- # The raw IPv6 address as a String.
-
- attr_reader :address
-
- def to_s # :nodoc:
- sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn")).sub(/(^|:)0(:0)+(:|$)/, '::')
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- ##
- # Turns this IPv6 address into a Gem::Resolv::DNS::Name.
- #--
- # ip6.arpa should be searched too. [RFC3152]
-
- def to_name
- return DNS::Name.new(
- @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa'])
- end
-
- def ==(other) # :nodoc:
- return @address == other.address
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @address.hash
- end
- end
-
- ##
- # Gem::Resolv::MDNS is a one-shot Multicast DNS (mDNS) resolver. It blindly
- # makes queries to the mDNS addresses without understanding anything about
- # multicast ports.
- #
- # Information taken form the following places:
- #
- # * RFC 6762
-
- class MDNS < DNS
-
- ##
- # Default mDNS Port
-
- Port = 5353
-
- ##
- # Default IPv4 mDNS address
-
- AddressV4 = '224.0.0.251'
-
- ##
- # Default IPv6 mDNS address
-
- AddressV6 = 'ff02::fb'
-
- ##
- # Default mDNS addresses
-
- Addresses = [
- [AddressV4, Port],
- [AddressV6, Port],
- ]
-
- ##
- # Creates a new one-shot Multicast DNS (mDNS) resolver.
- #
- # +config_info+ can be:
- #
- # nil::
- # Uses the default mDNS addresses
- #
- # Hash::
- # Must contain :nameserver or :nameserver_port like
- # Gem::Resolv::DNS#initialize.
-
- def initialize(config_info=nil)
- if config_info then
- super({ nameserver_port: Addresses }.merge(config_info))
- else
- super(nameserver_port: Addresses)
- end
- end
-
- ##
- # Iterates over all IP addresses for +name+ retrieved from the mDNS
- # resolver, provided name ends with "local". If the name does not end in
- # "local" no records will be returned.
- #
- # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved addresses will
- # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
-
- def each_address(name)
- name = Gem::Resolv::DNS::Name.create(name)
-
- return unless name[-1].to_s == 'local'
-
- super(name)
- end
-
- def make_udp_requester # :nodoc:
- nameserver_port = @config.nameserver_port
- Requester::MDNSOneShot.new(*nameserver_port)
- end
-
- end
-
- module LOC
-
- ##
- # A Gem::Resolv::LOC::Size
-
- class Size
-
- Regex = /^(\d+\.*\d*)[m]$/
-
- ##
- # Creates a new LOC::Size from +arg+ which may be:
- #
- # LOC::Size:: returns +arg+.
- # String:: +arg+ must match the LOC::Size::Regex constant
-
- def self.create(arg)
- case arg
- when Size
- return arg
- when String
- scalar = ''
- if Regex =~ arg
- scalar = [(($1.to_f*(1e2)).to_i.to_s[0].to_i*(2**4)+(($1.to_f*(1e2)).to_i.to_s.length-1))].pack("C")
- else
- raise ArgumentError.new("not a properly formed Size string: " + arg)
- end
- return Size.new(scalar)
- else
- raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}")
- end
- end
-
- def initialize(scalar)
- @scalar = scalar
- end
-
- ##
- # The raw size
-
- attr_reader :scalar
-
- def to_s # :nodoc:
- s = @scalar.unpack("H2").join.to_s
- return ((s[0].to_i)*(10**(s[1].to_i-2))).to_s << "m"
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- def ==(other) # :nodoc:
- return @scalar == other.scalar
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @scalar.hash
- end
-
- end
-
- ##
- # A Gem::Resolv::LOC::Coord
-
- class Coord
-
- Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/
-
- ##
- # Creates a new LOC::Coord from +arg+ which may be:
- #
- # LOC::Coord:: returns +arg+.
- # String:: +arg+ must match the LOC::Coord::Regex constant
-
- def self.create(arg)
- case arg
- when Coord
- return arg
- when String
- coordinates = ''
- if Regex =~ arg && $1.to_f < 180
- m = $~
- hemi = (m[4][/[NE]/]) || (m[4][/[SW]/]) ? 1 : -1
- coordinates = [ ((m[1].to_i*(36e5)) + (m[2].to_i*(6e4)) +
- (m[3].to_f*(1e3))) * hemi+(2**31) ].pack("N")
- orientation = m[4][/[NS]/] ? 'lat' : 'lon'
- else
- raise ArgumentError.new("not a properly formed Coord string: " + arg)
- end
- return Coord.new(coordinates,orientation)
- else
- raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}")
- end
- end
-
- def initialize(coordinates,orientation)
- unless coordinates.kind_of?(String)
- raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}")
- end
- unless orientation.kind_of?(String) && orientation[/^lon$|^lat$/]
- raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"')
- end
- @coordinates = coordinates
- @orientation = orientation
- end
-
- ##
- # The raw coordinates
-
- attr_reader :coordinates
-
- ## The orientation of the hemisphere as 'lat' or 'lon'
-
- attr_reader :orientation
-
- def to_s # :nodoc:
- c = @coordinates.unpack("N").join.to_i
- val = (c - (2**31)).abs
- fracsecs = (val % 1e3).to_i.to_s
- val = val / 1e3
- secs = (val % 60).to_i.to_s
- val = val / 60
- mins = (val % 60).to_i.to_s
- degs = (val / 60).to_i.to_s
- posi = (c >= 2**31)
- case posi
- when true
- hemi = @orientation[/^lat$/] ? "N" : "E"
- else
- hemi = @orientation[/^lon$/] ? "W" : "S"
- end
- return degs << " " << mins << " " << secs << "." << fracsecs << " " << hemi
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- def ==(other) # :nodoc:
- return @coordinates == other.coordinates
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @coordinates.hash
- end
-
- end
-
- ##
- # A Gem::Resolv::LOC::Alt
-
- class Alt
-
- Regex = /^([+-]*\d+\.*\d*)[m]$/
-
- ##
- # Creates a new LOC::Alt from +arg+ which may be:
- #
- # LOC::Alt:: returns +arg+.
- # String:: +arg+ must match the LOC::Alt::Regex constant
-
- def self.create(arg)
- case arg
- when Alt
- return arg
- when String
- altitude = ''
- if Regex =~ arg
- altitude = [($1.to_f*(1e2))+(1e7)].pack("N")
- else
- raise ArgumentError.new("not a properly formed Alt string: " + arg)
- end
- return Alt.new(altitude)
- else
- raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}")
- end
- end
-
- def initialize(altitude)
- @altitude = altitude
- end
-
- ##
- # The raw altitude
-
- attr_reader :altitude
-
- def to_s # :nodoc:
- a = @altitude.unpack("N").join.to_i
- return ((a.to_f/1e2)-1e5).to_s + "m"
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- def ==(other) # :nodoc:
- return @altitude == other.altitude
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @altitude.hash
- end
-
- end
-
- end
-
- ##
- # Default resolver to use for Gem::Resolv class methods.
-
- DefaultResolver = self.new
-
- ##
- # Replaces the resolvers in the default resolver with +new_resolvers+. This
- # allows resolvers to be changed for resolv-replace.
-
- def DefaultResolver.replace_resolvers new_resolvers
- @resolvers = new_resolvers
- end
-
- ##
- # Address Regexp to use for matching IP addresses.
-
- AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
-
-end
-
diff --git a/lib/rubygems/vendor/securerandom/.document b/lib/rubygems/vendor/securerandom/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/securerandom/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/securerandom/lib/random/formatter.rb b/lib/rubygems/vendor/securerandom/lib/random/formatter.rb
deleted file mode 100644
index 3544033340..0000000000
--- a/lib/rubygems/vendor/securerandom/lib/random/formatter.rb
+++ /dev/null
@@ -1,373 +0,0 @@
-# -*- coding: us-ascii -*-
-# frozen_string_literal: true
-
-# == \Random number formatter.
-#
-# Formats generated random numbers in many manners. When <tt>'random/formatter'</tt>
-# is required, several methods are added to empty core module <tt>Gem::Random::Formatter</tt>,
-# making them available as Random's instance and module methods.
-#
-# Standard library Gem::SecureRandom is also extended with the module, and the methods
-# described below are available as a module methods in it.
-#
-# === Examples
-#
-# Generate random hexadecimal strings:
-#
-# require 'rubygems/vendor/securerandom/lib/random/formatter'
-#
-# prng = Random.new
-# prng.hex(10) #=> "52750b30ffbc7de3b362"
-# prng.hex(10) #=> "92b15d6c8dc4beb5f559"
-# prng.hex(13) #=> "39b290146bea6ce975c37cfc23"
-# # or just
-# Random.hex #=> "1aed0c631e41be7f77365415541052ee"
-#
-# Generate random base64 strings:
-#
-# prng.base64(10) #=> "EcmTPZwWRAozdA=="
-# prng.base64(10) #=> "KO1nIU+p9DKxGg=="
-# prng.base64(12) #=> "7kJSM/MzBJI+75j8"
-# Random.base64(4) #=> "bsQ3fQ=="
-#
-# Generate random binary strings:
-#
-# prng.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
-# prng.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
-# Random.random_bytes(6) #=> "\xA1\xE6Lr\xC43"
-#
-# Generate alphanumeric strings:
-#
-# prng.alphanumeric(10) #=> "S8baxMJnPl"
-# prng.alphanumeric(10) #=> "aOxAg8BAJe"
-# Random.alphanumeric #=> "TmP9OsJHJLtaZYhP"
-#
-# Generate UUIDs:
-#
-# prng.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
-# prng.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
-# Random.uuid #=> "f14e0271-de96-45cc-8911-8910292a42cd"
-#
-# All methods are available in the standard library Gem::SecureRandom, too:
-#
-# Gem::SecureRandom.hex #=> "05b45376a30c67238eb93b16499e50cf"
-
-module Gem::Random::Formatter
-
- # Generate a random binary string.
- #
- # The argument _n_ specifies the length of the result string.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in future.
- #
- # The result may contain any byte: "\x00" - "\xff".
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6"
- # # or
- # prng = Random.new
- # prng.random_bytes #=> "m\xDC\xFC/\a\x00Uf\xB2\xB2P\xBD\xFF6S\x97"
- def random_bytes(n=nil)
- n = n ? n.to_int : 16
- gen_random(n)
- end
-
- # Generate a random hexadecimal string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number to be generated.
- # The length of the resulting hexadecimal string is twice of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The result may contain 0-9 and a-f.
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"
- # # or
- # prng = Random.new
- # prng.hex #=> "91dc3bfb4de5b11d029d376634589b61"
- def hex(n=nil)
- random_bytes(n).unpack1("H*")
- end
-
- # Generate a random base64 string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number
- # to be generated. The length of the result string is about 4/3 of _n_.
- #
- # 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, 0-9, "+", "/" and "=".
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A=="
- # # or
- # prng = Random.new
- # prng.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
- #
- # See RFC 3548 for the definition of base64.
- def base64(n=nil)
- [random_bytes(n)].pack("m0")
- end
-
- # Generate a random URL-safe base64 string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number
- # to be generated. The length of the result string is about 4/3 of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The boolean argument _padding_ specifies the padding.
- # If it is false or nil, padding is not generated.
- # Otherwise padding is generated.
- # By default, padding is not generated because "=" may be used as a URL delimiter.
- #
- # The result may contain A-Z, a-z, 0-9, "-" and "_".
- # "=" is also used if _padding_ is true.
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg"
- # # or
- # prng = Random.new
- # prng.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
- #
- # prng.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
- # prng.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="
- #
- # See RFC 3548 for the definition of URL-safe base64.
- def urlsafe_base64(n=nil, padding=false)
- s = [random_bytes(n)].pack("m0")
- s.tr!("+/", "-_")
- s.delete!("=") unless padding
- s
- end
-
- # Generate a random v4 UUID (Universally Unique IDentifier).
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
- # Random.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
- # # or
- # prng = Random.new
- # prng.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"
- #
- # The version 4 UUID is purely random (except the version).
- # It doesn't contain meaningful information such as MAC addresses, timestamps, etc.
- #
- # The result contains 122 random bits (15.25 random bytes).
- #
- # See RFC4122[https://datatracker.ietf.org/doc/html/rfc4122] for details of UUID.
- #
- def uuid
- ary = random_bytes(16).unpack("NnnnnN")
- ary[2] = (ary[2] & 0x0fff) | 0x4000
- ary[3] = (ary[3] & 0x3fff) | 0x8000
- "%08x-%04x-%04x-%04x-%04x%08x" % ary
- end
-
- alias uuid_v4 uuid
-
- # Generate a random v7 UUID (Universally Unique IDentifier).
- #
- # require 'rubygems/vendor/securerandom/lib/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 because its output
- # includes not only random bits but also timestamp.
- #
- # 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
-
- # Internal interface to Random; Generate random data _n_ bytes.
- private def gen_random(n)
- self.bytes(n)
- end
-
- # Generate a string that randomly draws from a
- # source array of characters.
- #
- # The argument _source_ specifies the array of characters from which
- # to generate the string.
- # The argument _n_ specifies the length, in characters, of the string to be
- # generated.
- #
- # The result may contain whatever characters are in the source array.
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # prng.choose([*'l'..'r'], 16) #=> "lmrqpoonmmlqlron"
- # prng.choose([*'0'..'9'], 5) #=> "27309"
- private def choose(source, n)
- size = source.size
- m = 1
- limit = size
- while limit * size <= 0x100000000
- limit *= size
- m += 1
- end
- result = ''.dup
- while m <= n
- rs = random_number(limit)
- is = rs.digits(size)
- (m-is.length).times { is << 0 }
- result << source.values_at(*is).join('')
- n -= m
- end
- if 0 < n
- rs = random_number(limit)
- is = rs.digits(size)
- if is.length < n
- (n-is.length).times { is << 0 }
- else
- is.pop while n < is.length
- end
- result.concat source.values_at(*is).join('')
- end
- result
- end
-
- # The default character list for #alphanumeric.
- ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
-
- # Generate a random alphanumeric string.
- #
- # 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.
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.alphanumeric #=> "2BuBuLf3WfSKyQbR"
- # # 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)
- n = 16 if n.nil?
- choose(chars, n)
- end
-end
diff --git a/lib/rubygems/vendor/securerandom/lib/securerandom.rb b/lib/rubygems/vendor/securerandom/lib/securerandom.rb
deleted file mode 100644
index f83d2a74fc..0000000000
--- a/lib/rubygems/vendor/securerandom/lib/securerandom.rb
+++ /dev/null
@@ -1,96 +0,0 @@
-# -*- coding: us-ascii -*-
-# frozen_string_literal: true
-
-require_relative 'random/formatter'
-
-# == Secure random number generator interface.
-#
-# This library is an interface to secure random number generators which are
-# suitable for generating session keys in HTTP cookies, etc.
-#
-# You can use this library in your application by requiring it:
-#
-# require 'rubygems/vendor/securerandom/lib/securerandom'
-#
-# It supports the following secure random number generators:
-#
-# * openssl
-# * /dev/urandom
-# * Win32
-#
-# Gem::SecureRandom is extended by the Gem::Random::Formatter module which
-# defines the following methods:
-#
-# * alphanumeric
-# * base64
-# * choose
-# * gen_random
-# * hex
-# * rand
-# * random_bytes
-# * random_number
-# * urlsafe_base64
-# * uuid
-#
-# These methods are usable as class methods of Gem::SecureRandom such as
-# +Gem::SecureRandom.hex+.
-#
-# If a secure random number generator is not available,
-# +NotImplementedError+ is raised.
-
-module Gem::SecureRandom
-
- # The version
- VERSION = "0.3.1"
-
- class << self
- # Returns a random binary string containing +size+ bytes.
- #
- # See Random.bytes
- def bytes(n)
- return gen_random(n)
- end
-
- private
-
- # :stopdoc:
-
- # Implementation using OpenSSL
- def gen_random_openssl(n)
- return OpenSSL::Random.random_bytes(n)
- end
-
- # Implementation using system random device
- def gen_random_urandom(n)
- ret = Random.urandom(n)
- unless ret
- raise NotImplementedError, "No random device"
- end
- unless ret.length == n
- raise NotImplementedError, "Unexpected partial read from random device: only #{ret.length} for #{n} bytes"
- end
- ret
- end
-
- begin
- # Check if Random.urandom is available
- Random.urandom(1)
- alias gen_random gen_random_urandom
- rescue RuntimeError
- begin
- require 'openssl'
- rescue NoMethodError
- raise NotImplementedError, "No random device"
- else
- alias gen_random gen_random_openssl
- end
- end
-
- # :startdoc:
-
- # Generate random data bytes for Gem::Random::Formatter
- public :gen_random
- end
-end
-
-Gem::SecureRandom.extend(Gem::Random::Formatter)
diff --git a/lib/rubygems/vendor/timeout/.document b/lib/rubygems/vendor/timeout/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/timeout/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/timeout/lib/timeout.rb b/lib/rubygems/vendor/timeout/lib/timeout.rb
deleted file mode 100644
index df97d64ca0..0000000000
--- a/lib/rubygems/vendor/timeout/lib/timeout.rb
+++ /dev/null
@@ -1,199 +0,0 @@
-# frozen_string_literal: true
-# Timeout long-running blocks
-#
-# == Synopsis
-#
-# require 'rubygems/vendor/timeout/lib/timeout'
-# status = Gem::Timeout::timeout(5) {
-# # Something that should be interrupted if it takes more than 5 seconds...
-# }
-#
-# == Description
-#
-# Gem::Timeout provides a way to auto-terminate a potentially long-running
-# operation if it hasn't finished in a fixed amount of time.
-#
-# Previous versions didn't use a module for namespacing, however
-# #timeout is provided for backwards compatibility. You
-# should prefer Gem::Timeout.timeout instead.
-#
-# == Copyright
-#
-# Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc.
-# Copyright:: (C) 2000 Information-technology Promotion Agency, Japan
-
-module Gem::Timeout
- VERSION = "0.4.1"
-
- # Internal error raised to when a timeout is triggered.
- class ExitException < Exception
- def exception(*)
- self
- end
- end
-
- # Raised by Gem::Timeout.timeout when the block times out.
- class Error < RuntimeError
- def self.handle_timeout(message)
- exc = ExitException.new(message)
-
- begin
- yield exc
- rescue ExitException => e
- raise new(message) if exc.equal?(e)
- raise
- end
- end
- end
-
- # :stopdoc:
- CONDVAR = ConditionVariable.new
- QUEUE = Queue.new
- QUEUE_MUTEX = Mutex.new
- TIMEOUT_THREAD_MUTEX = Mutex.new
- @timeout_thread = nil
- private_constant :CONDVAR, :QUEUE, :QUEUE_MUTEX, :TIMEOUT_THREAD_MUTEX
-
- class Request
- attr_reader :deadline
-
- def initialize(thread, timeout, exception_class, message)
- @thread = thread
- @deadline = GET_TIME.call(Process::CLOCK_MONOTONIC) + timeout
- @exception_class = exception_class
- @message = message
-
- @mutex = Mutex.new
- @done = false # protected by @mutex
- end
-
- def done?
- @mutex.synchronize do
- @done
- end
- end
-
- def expired?(now)
- now >= @deadline
- end
-
- def interrupt
- @mutex.synchronize do
- unless @done
- @thread.raise @exception_class, @message
- @done = true
- end
- end
- end
-
- def finished
- @mutex.synchronize do
- @done = true
- end
- end
- end
- private_constant :Request
-
- def self.create_timeout_thread
- watcher = Thread.new do
- requests = []
- while true
- until QUEUE.empty? and !requests.empty? # wait to have at least one request
- req = QUEUE.pop
- requests << req unless req.done?
- end
- closest_deadline = requests.min_by(&:deadline).deadline
-
- now = 0.0
- QUEUE_MUTEX.synchronize do
- while (now = GET_TIME.call(Process::CLOCK_MONOTONIC)) < closest_deadline and QUEUE.empty?
- CONDVAR.wait(QUEUE_MUTEX, closest_deadline - now)
- end
- end
-
- requests.each do |req|
- req.interrupt if req.expired?(now)
- end
- requests.reject!(&:done?)
- end
- end
- ThreadGroup::Default.add(watcher) unless watcher.group.enclosed?
- watcher.name = "Gem::Timeout stdlib thread"
- watcher.thread_variable_set(:"\0__detached_thread__", true)
- watcher
- end
- private_class_method :create_timeout_thread
-
- def self.ensure_timeout_thread_created
- unless @timeout_thread and @timeout_thread.alive?
- TIMEOUT_THREAD_MUTEX.synchronize do
- unless @timeout_thread and @timeout_thread.alive?
- @timeout_thread = create_timeout_thread
- end
- end
- end
- end
-
- # We keep a private reference so that time mocking libraries won't break
- # Gem::Timeout.
- GET_TIME = Process.method(:clock_gettime)
- private_constant :GET_TIME
-
- # :startdoc:
-
- # Perform an operation in a block, raising an error if it takes longer than
- # +sec+ seconds to complete.
- #
- # +sec+:: Number of seconds to wait for the block to terminate. Any number
- # may be used, including Floats to specify fractional seconds. A
- # value of 0 or +nil+ will execute the block without any timeout.
- # +klass+:: Exception Class to raise if the block fails to terminate
- # in +sec+ seconds. Omitting will use the default, Gem::Timeout::Error
- # +message+:: Error message to raise with Exception Class.
- # Omitting will use the default, "execution expired"
- #
- # Returns the result of the block *if* the block completed before
- # +sec+ seconds, otherwise throws an exception, based on the value of +klass+.
- #
- # The exception thrown to terminate the given block cannot be rescued inside
- # the block unless +klass+ is given explicitly. However, the block can use
- # ensure to prevent the handling of the exception. For that reason, this
- # method cannot be relied on to enforce timeouts for untrusted blocks.
- #
- # If a scheduler is defined, it will be used to handle the timeout by invoking
- # Scheduler#timeout_after.
- #
- # Note that this is both a method of module Gem::Timeout, so you can <tt>include
- # Gem::Timeout</tt> into your classes so they have a #timeout method, as well as
- # a module method, so you can call it directly as Gem::Timeout.timeout().
- def timeout(sec, klass = nil, message = nil, &block) #:yield: +sec+
- return yield(sec) if sec == nil or sec.zero?
-
- message ||= "execution expired"
-
- if Fiber.respond_to?(:current_scheduler) && (scheduler = Fiber.current_scheduler)&.respond_to?(:timeout_after)
- return scheduler.timeout_after(sec, klass || Error, message, &block)
- end
-
- Gem::Timeout.ensure_timeout_thread_created
- perform = Proc.new do |exc|
- request = Request.new(Thread.current, sec, exc, message)
- QUEUE_MUTEX.synchronize do
- QUEUE << request
- CONDVAR.signal
- end
- begin
- return yield(sec)
- ensure
- request.finished
- end
- end
-
- if klass
- perform.call(klass)
- else
- Error.handle_timeout(message, &perform)
- end
- end
- module_function :timeout
-end
diff --git a/lib/rubygems/vendor/tsort/.document b/lib/rubygems/vendor/tsort/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/tsort/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/tsort/lib/tsort.rb b/lib/rubygems/vendor/tsort/lib/tsort.rb
deleted file mode 100644
index 9dd7c09521..0000000000
--- a/lib/rubygems/vendor/tsort/lib/tsort.rb
+++ /dev/null
@@ -1,455 +0,0 @@
-# frozen_string_literal: true
-
-#--
-# tsort.rb - provides a module for topological sorting and strongly connected components.
-#++
-#
-
-#
-# Gem::TSort implements topological sorting using Tarjan's algorithm for
-# strongly connected components.
-#
-# Gem::TSort is designed to be able to be used with any object which can be
-# interpreted as a directed graph.
-#
-# Gem::TSort requires two methods to interpret an object as a graph,
-# tsort_each_node and tsort_each_child.
-#
-# * tsort_each_node is used to iterate for all nodes over a graph.
-# * tsort_each_child is used to iterate for child nodes of a given node.
-#
-# The equality of nodes are defined by eql? and hash since
-# Gem::TSort uses Hash internally.
-#
-# == A Simple Example
-#
-# The following example demonstrates how to mix the Gem::TSort module into an
-# existing class (in this case, Hash). Here, we're treating each key in
-# the hash as a node in the graph, and so we simply alias the required
-# #tsort_each_node method to Hash's #each_key method. For each key in the
-# hash, the associated value is an array of the node's child nodes. This
-# choice in turn leads to our implementation of the required #tsort_each_child
-# method, which fetches the array of child nodes and then iterates over that
-# array using the user-supplied block.
-#
-# require 'rubygems/vendor/tsort/lib/tsort'
-#
-# class Hash
-# include Gem::TSort
-# alias tsort_each_node each_key
-# def tsort_each_child(node, &block)
-# fetch(node).each(&block)
-# end
-# end
-#
-# {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort
-# #=> [3, 2, 1, 4]
-#
-# {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components
-# #=> [[4], [2, 3], [1]]
-#
-# == A More Realistic Example
-#
-# A very simple `make' like tool can be implemented as follows:
-#
-# require 'rubygems/vendor/tsort/lib/tsort'
-#
-# class Make
-# def initialize
-# @dep = {}
-# @dep.default = []
-# end
-#
-# def rule(outputs, inputs=[], &block)
-# triple = [outputs, inputs, block]
-# outputs.each {|f| @dep[f] = [triple]}
-# @dep[triple] = inputs
-# end
-#
-# def build(target)
-# each_strongly_connected_component_from(target) {|ns|
-# if ns.length != 1
-# fs = ns.delete_if {|n| Array === n}
-# raise Gem::TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
-# end
-# n = ns.first
-# if Array === n
-# outputs, inputs, block = n
-# inputs_time = inputs.map {|f| File.mtime f}.max
-# begin
-# outputs_time = outputs.map {|f| File.mtime f}.min
-# rescue Errno::ENOENT
-# outputs_time = nil
-# end
-# if outputs_time == nil ||
-# inputs_time != nil && outputs_time <= inputs_time
-# sleep 1 if inputs_time != nil && inputs_time.to_i == Time.now.to_i
-# block.call
-# end
-# end
-# }
-# end
-#
-# def tsort_each_child(node, &block)
-# @dep[node].each(&block)
-# end
-# include Gem::TSort
-# end
-#
-# def command(arg)
-# print arg, "\n"
-# system arg
-# end
-#
-# m = Make.new
-# m.rule(%w[t1]) { command 'date > t1' }
-# m.rule(%w[t2]) { command 'date > t2' }
-# m.rule(%w[t3]) { command 'date > t3' }
-# m.rule(%w[t4], %w[t1 t3]) { command 'cat t1 t3 > t4' }
-# m.rule(%w[t5], %w[t4 t2]) { command 'cat t4 t2 > t5' }
-# m.build('t5')
-#
-# == Bugs
-#
-# * 'tsort.rb' is wrong name because this library uses
-# Tarjan's algorithm for strongly connected components.
-# Although 'strongly_connected_components.rb' is correct but too long.
-#
-# == References
-#
-# R. E. Tarjan, "Depth First Search and Linear Graph Algorithms",
-# <em>SIAM Journal on Computing</em>, Vol. 1, No. 2, pp. 146-160, June 1972.
-#
-
-module Gem::TSort
-
- VERSION = "0.2.0"
-
- class Cyclic < StandardError
- end
-
- # Returns a topologically sorted array of nodes.
- # The array is sorted from children to parents, i.e.
- # the first element has no child and the last node has no parent.
- #
- # If there is a cycle, Gem::TSort::Cyclic is raised.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # p graph.tsort #=> [4, 2, 3, 1]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # p graph.tsort # raises Gem::TSort::Cyclic
- #
- def tsort
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- Gem::TSort.tsort(each_node, each_child)
- end
-
- # Returns a topologically sorted array of nodes.
- # The array is sorted from children to parents, i.e.
- # the first element has no child and the last node has no parent.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # If there is a cycle, Gem::TSort::Cyclic is raised.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p Gem::TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
- #
- # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p Gem::TSort.tsort(each_node, each_child) # raises Gem::TSort::Cyclic
- #
- def self.tsort(each_node, each_child)
- tsort_each(each_node, each_child).to_a
- end
-
- # The iterator version of the #tsort method.
- # <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
- # modification of _obj_ during the iteration may lead to unexpected results.
- #
- # #tsort_each returns +nil+.
- # If there is a cycle, Gem::TSort::Cyclic is raised.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # graph.tsort_each {|n| p n }
- # #=> 4
- # # 2
- # # 3
- # # 1
- #
- def tsort_each(&block) # :yields: node
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- Gem::TSort.tsort_each(each_node, each_child, &block)
- end
-
- # The iterator version of the Gem::TSort.tsort method.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # Gem::TSort.tsort_each(each_node, each_child) {|n| p n }
- # #=> 4
- # # 2
- # # 3
- # # 1
- #
- def self.tsort_each(each_node, each_child) # :yields: node
- return to_enum(__method__, each_node, each_child) unless block_given?
-
- each_strongly_connected_component(each_node, each_child) {|component|
- if component.size == 1
- yield component.first
- else
- raise Cyclic.new("topological sort failed: #{component.inspect}")
- end
- }
- end
-
- # Returns strongly connected components as an array of arrays of nodes.
- # The array is sorted from children to parents.
- # Each elements of the array represents a strongly connected component.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
- #
- def strongly_connected_components
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- Gem::TSort.strongly_connected_components(each_node, each_child)
- end
-
- # Returns strongly connected components as an array of arrays of nodes.
- # The array is sorted from children to parents.
- # Each elements of the array represents a strongly connected component.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p Gem::TSort.strongly_connected_components(each_node, each_child)
- # #=> [[4], [2], [3], [1]]
- #
- # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p Gem::TSort.strongly_connected_components(each_node, each_child)
- # #=> [[4], [2, 3], [1]]
- #
- def self.strongly_connected_components(each_node, each_child)
- each_strongly_connected_component(each_node, each_child).to_a
- end
-
- # The iterator version of the #strongly_connected_components method.
- # <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
- # <tt><em>obj</em>.strongly_connected_components.each</tt>, but
- # modification of _obj_ during the iteration may lead to unexpected results.
- #
- # #each_strongly_connected_component returns +nil+.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # graph.each_strongly_connected_component {|scc| p scc }
- # #=> [4]
- # # [2]
- # # [3]
- # # [1]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # graph.each_strongly_connected_component {|scc| p scc }
- # #=> [4]
- # # [2, 3]
- # # [1]
- #
- def each_strongly_connected_component(&block) # :yields: nodes
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- Gem::TSort.each_strongly_connected_component(each_node, each_child, &block)
- end
-
- # The iterator version of the Gem::TSort.strongly_connected_components method.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
- # #=> [4]
- # # [2]
- # # [3]
- # # [1]
- #
- # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
- # #=> [4]
- # # [2, 3]
- # # [1]
- #
- def self.each_strongly_connected_component(each_node, each_child) # :yields: nodes
- return to_enum(__method__, each_node, each_child) unless block_given?
-
- id_map = {}
- stack = []
- each_node.call {|node|
- unless id_map.include? node
- each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
- yield c
- }
- end
- }
- nil
- end
-
- # Iterates over strongly connected component in the subgraph reachable from
- # _node_.
- #
- # Return value is unspecified.
- #
- # #each_strongly_connected_component_from doesn't call #tsort_each_node.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # graph.each_strongly_connected_component_from(2) {|scc| p scc }
- # #=> [4]
- # # [2]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # graph.each_strongly_connected_component_from(2) {|scc| p scc }
- # #=> [4]
- # # [2, 3]
- #
- def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
- Gem::TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
- end
-
- # Iterates over strongly connected components in a graph.
- # The graph is represented by _node_ and _each_child_.
- #
- # _node_ is the first node.
- # _each_child_ should have +call+ method which takes a node argument
- # and yields for each child node.
- #
- # Return value is unspecified.
- #
- # #Gem::TSort.each_strongly_connected_component_from is a class method and
- # it doesn't need a class to represent a graph which includes Gem::TSort.
- #
- # graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_child = lambda {|n, &b| graph[n].each(&b) }
- # Gem::TSort.each_strongly_connected_component_from(1, each_child) {|scc|
- # p scc
- # }
- # #=> [4]
- # # [2, 3]
- # # [1]
- #
- def self.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
- return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
-
- minimum_id = node_id = id_map[node] = id_map.size
- stack_length = stack.length
- stack << node
-
- each_child.call(node) {|child|
- if id_map.include? child
- child_id = id_map[child]
- minimum_id = child_id if child_id && child_id < minimum_id
- else
- sub_minimum_id =
- each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
- yield c
- }
- minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
- end
- }
-
- if node_id == minimum_id
- component = stack.slice!(stack_length .. -1)
- component.each {|n| id_map[n] = nil}
- yield component
- end
-
- minimum_id
- end
-
- # Should be implemented by a extended class.
- #
- # #tsort_each_node is used to iterate for all nodes over a graph.
- #
- def tsort_each_node # :yields: node
- raise NotImplementedError.new
- end
-
- # Should be implemented by a extended class.
- #
- # #tsort_each_child is used to iterate for child nodes of _node_.
- #
- def tsort_each_child(node) # :yields: child
- raise NotImplementedError.new
- end
-end
diff --git a/lib/rubygems/vendor/uri/.document b/lib/rubygems/vendor/uri/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/uri/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/uri/lib/uri.rb b/lib/rubygems/vendor/uri/lib/uri.rb
deleted file mode 100644
index f1ccc167cc..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-# frozen_string_literal: false
-# Gem::URI is a module providing classes to handle Uniform Resource Identifiers
-# (RFC2396[http://tools.ietf.org/html/rfc2396]).
-#
-# == Features
-#
-# * Uniform way of handling URIs.
-# * Flexibility to introduce custom Gem::URI schemes.
-# * Flexibility to have an alternate Gem::URI::Parser (or just different patterns
-# and regexp's).
-#
-# == Basic example
-#
-# require 'rubygems/vendor/uri/lib/uri'
-#
-# uri = Gem::URI("http://foo.com/posts?id=30&limit=5#time=1305298413")
-# #=> #<Gem::URI::HTTP http://foo.com/posts?id=30&limit=5#time=1305298413>
-#
-# uri.scheme #=> "http"
-# uri.host #=> "foo.com"
-# uri.path #=> "/posts"
-# uri.query #=> "id=30&limit=5"
-# uri.fragment #=> "time=1305298413"
-#
-# uri.to_s #=> "http://foo.com/posts?id=30&limit=5#time=1305298413"
-#
-# == Adding custom URIs
-#
-# module Gem::URI
-# class RSYNC < Generic
-# DEFAULT_PORT = 873
-# end
-# register_scheme 'RSYNC', RSYNC
-# end
-# #=> Gem::URI::RSYNC
-#
-# Gem::URI.scheme_list
-# #=> {"FILE"=>Gem::URI::File, "FTP"=>Gem::URI::FTP, "HTTP"=>Gem::URI::HTTP,
-# # "HTTPS"=>Gem::URI::HTTPS, "LDAP"=>Gem::URI::LDAP, "LDAPS"=>Gem::URI::LDAPS,
-# # "MAILTO"=>Gem::URI::MailTo, "RSYNC"=>Gem::URI::RSYNC}
-#
-# uri = Gem::URI("rsync://rsync.foo.com")
-# #=> #<Gem::URI::RSYNC rsync://rsync.foo.com>
-#
-# == RFC References
-#
-# A good place to view an RFC spec is http://www.ietf.org/rfc.html.
-#
-# Here is a list of all related RFC's:
-# - RFC822[http://tools.ietf.org/html/rfc822]
-# - RFC1738[http://tools.ietf.org/html/rfc1738]
-# - RFC2255[http://tools.ietf.org/html/rfc2255]
-# - RFC2368[http://tools.ietf.org/html/rfc2368]
-# - RFC2373[http://tools.ietf.org/html/rfc2373]
-# - RFC2396[http://tools.ietf.org/html/rfc2396]
-# - RFC2732[http://tools.ietf.org/html/rfc2732]
-# - RFC3986[http://tools.ietf.org/html/rfc3986]
-#
-# == Class tree
-#
-# - Gem::URI::Generic (in uri/generic.rb)
-# - Gem::URI::File - (in uri/file.rb)
-# - Gem::URI::FTP - (in uri/ftp.rb)
-# - Gem::URI::HTTP - (in uri/http.rb)
-# - Gem::URI::HTTPS - (in uri/https.rb)
-# - Gem::URI::LDAP - (in uri/ldap.rb)
-# - Gem::URI::LDAPS - (in uri/ldaps.rb)
-# - Gem::URI::MailTo - (in uri/mailto.rb)
-# - Gem::URI::Parser - (in uri/common.rb)
-# - Gem::URI::REGEXP - (in uri/common.rb)
-# - Gem::URI::REGEXP::PATTERN - (in uri/common.rb)
-# - Gem::URI::Util - (in uri/common.rb)
-# - Gem::URI::Error - (in uri/common.rb)
-# - Gem::URI::InvalidURIError - (in uri/common.rb)
-# - Gem::URI::InvalidComponentError - (in uri/common.rb)
-# - Gem::URI::BadURIError - (in uri/common.rb)
-#
-# == Copyright Info
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# Documentation::
-# Akira Yamada <akira@ruby-lang.org>
-# Dmitry V. Sabanin <sdmitry@lrn.ru>
-# Vincent Batts <vbatts@hashbangbash.com>
-# License::
-# Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
-# You can redistribute it and/or modify it under the same term as Ruby.
-#
-
-module Gem::URI
-end
-
-require_relative 'uri/version'
-require_relative 'uri/common'
-require_relative 'uri/generic'
-require_relative 'uri/file'
-require_relative 'uri/ftp'
-require_relative 'uri/http'
-require_relative 'uri/https'
-require_relative 'uri/ldap'
-require_relative 'uri/ldaps'
-require_relative 'uri/mailto'
-require_relative 'uri/ws'
-require_relative 'uri/wss'
diff --git a/lib/rubygems/vendor/uri/lib/uri/common.rb b/lib/rubygems/vendor/uri/lib/uri/common.rb
deleted file mode 100644
index 02b12d06e6..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/common.rb
+++ /dev/null
@@ -1,855 +0,0 @@
-# frozen_string_literal: true
-#--
-# = uri/common.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License::
-# You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative "rfc2396_parser"
-require_relative "rfc3986_parser"
-
-module Gem::URI
- include RFC2396_REGEXP
-
- REGEXP = RFC2396_REGEXP
- 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)
-
- # Gem::URI::Parser.new
- DEFAULT_PARSER = Parser.new
- DEFAULT_PARSER.pattern.each_pair do |sym, str|
- unless REGEXP::PATTERN.const_defined?(sym)
- REGEXP::PATTERN.const_set(sym, str)
- end
- end
- DEFAULT_PARSER.regexp.each_pair do |sym, str|
- const_set(sym, str)
- end
- Ractor.make_shareable(DEFAULT_PARSER) if defined?(Ractor)
-
- module Util # :nodoc:
- def make_components_hash(klass, array_hash)
- tmp = {}
- if array_hash.kind_of?(Array) &&
- array_hash.size == klass.component.size - 1
- klass.component[1..-1].each_index do |i|
- begin
- tmp[klass.component[i + 1]] = array_hash[i].clone
- rescue TypeError
- tmp[klass.component[i + 1]] = array_hash[i]
- end
- end
-
- elsif array_hash.kind_of?(Hash)
- array_hash.each do |key, value|
- begin
- tmp[key] = value.clone
- rescue TypeError
- tmp[key] = value
- end
- end
- else
- raise ArgumentError,
- "expected Array of or Hash of components of #{klass} (#{klass.component[1..-1].join(', ')})"
- end
- tmp[:scheme] = klass.to_s.sub(/\A.*::/, '').downcase
-
- return tmp
- end
- module_function :make_components_hash
- end
-
- module Schemes
- end
- private_constant :Schemes
-
- # Registers the given +klass+ as the class to be instantiated
- # when parsing a \Gem::URI with the given +scheme+:
- #
- # Gem::URI.register_scheme('MS_SEARCH', Gem::URI::Generic) # => Gem::URI::Generic
- # Gem::URI.scheme_list['MS_SEARCH'] # => Gem::URI::Generic
- #
- # 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:
- #
- # Gem::URI.scheme_list
- # # =>
- # {"MAILTO"=>Gem::URI::MailTo,
- # "LDAPS"=>Gem::URI::LDAPS,
- # "WS"=>Gem::URI::WS,
- # "HTTP"=>Gem::URI::HTTP,
- # "HTTPS"=>Gem::URI::HTTPS,
- # "LDAP"=>Gem::URI::LDAP,
- # "FILE"=>Gem::URI::File,
- # "FTP"=>Gem::URI::FTP}
- #
- # Related: Gem::URI.register_scheme.
- def self.scheme_list
- Schemes.constants.map { |name|
- [name.to_s.upcase, Schemes.const_get(name)]
- }.to_h
- end
-
- INITIAL_SCHEMES = scheme_list
- 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>Gem::URI.scheme_list[scheme.upcase]</tt>.
- # - The object is initialized by calling the class initializer
- # using +scheme+ and +arguments+.
- # See Gem::URI::Generic.new.
- #
- # Examples:
- #
- # values = ['john.doe', 'www.example.com', '123', nil, '/forum/questions/', nil, 'tag=networking&order=newest', 'top']
- # Gem::URI.for('https', *values)
- # # => #<Gem::URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # Gem::URI.for('foo', *values, default: Gem::URI::HTTP)
- # # => #<Gem::URI::HTTP foo://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- #
- def self.for(scheme, *arguments, default: Generic)
- const_name = scheme.to_s.upcase
-
- uri_class = INITIAL_SCHEMES[const_name]
- uri_class ||= if /\A[A-Z]\w*\z/.match?(const_name) && Schemes.const_defined?(const_name, false)
- Schemes.const_get(const_name, false)
- end
- uri_class ||= default
-
- return uri_class.new(scheme, *arguments)
- end
-
- #
- # Base class for all Gem::URI exceptions.
- #
- class Error < StandardError; end
- #
- # Not a Gem::URI.
- #
- class InvalidURIError < Error; end
- #
- # Not a Gem::URI component.
- #
- class InvalidComponentError < Error; end
- #
- # Gem::URI is valid, bad usage is not.
- #
- class BadURIError < Error; end
-
- # Returns a 9-element array representing the parts of the \Gem::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 = Gem::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"]]
- #
- def self.split(uri)
- RFC3986_PARSER.split(uri)
- end
-
- # Returns a new \Gem::URI object constructed from the given string +uri+:
- #
- # Gem::URI.parse('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<Gem::URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # Gem::URI.parse('http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<Gem::URI::HTTP http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- #
- # It's recommended to first ::escape string +uri+
- # if it may contain invalid Gem::URI characters.
- #
- def self.parse(uri)
- RFC3986_PARSER.parse(uri)
- end
-
- # Merges the given Gem::URI strings +str+
- # per {RFC 2396}[https://www.rfc-editor.org/rfc/rfc2396.html].
- #
- # Each string in +str+ is converted to an
- # {RFC3986 Gem::URI}[https://www.rfc-editor.org/rfc/rfc3986.html] before being merged.
- #
- # Examples:
- #
- # Gem::URI.join("http://example.com/","main.rbx")
- # # => #<Gem::URI::HTTP http://example.com/main.rbx>
- #
- # Gem::URI.join('http://example.com', 'foo')
- # # => #<Gem::URI::HTTP http://example.com/foo>
- #
- # Gem::URI.join('http://example.com', '/foo', '/bar')
- # # => #<Gem::URI::HTTP http://example.com/bar>
- #
- # Gem::URI.join('http://example.com', '/foo', 'bar')
- # # => #<Gem::URI::HTTP http://example.com/bar>
- #
- # Gem::URI.join('http://example.com', '/foo/', 'bar')
- # # => #<Gem::URI::HTTP http://example.com/foo/bar>
- #
- def self.join(*str)
- RFC3986_PARSER.join(*str)
- end
-
- #
- # == Synopsis
- #
- # Gem::URI::extract(str[, schemes][,&blk])
- #
- # == Args
- #
- # +str+::
- # String to extract URIs from.
- # +schemes+::
- # Limit Gem::URI matching to specific schemes.
- #
- # == Description
- #
- # Extracts URIs from a string. If block given, iterates through all matched URIs.
- # Returns nil if block given or array with matches.
- #
- # == Usage
- #
- # require "rubygems/vendor/uri/lib/uri"
- #
- # Gem::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:
- warn "Gem::URI.extract is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.extract(str, schemes, &block)
- end
-
- #
- # == Synopsis
- #
- # Gem::URI::regexp([match_schemes])
- #
- # == Args
- #
- # +match_schemes+::
- # Array of schemes. If given, resulting regexp matches to URIs
- # whose scheme is one of the match_schemes.
- #
- # == Description
- #
- # Returns a Regexp object which matches to Gem::URI-like strings.
- # The Regexp object returned by this method includes arbitrary
- # number of capture group (parentheses). Never rely on its number.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # # extract first Gem::URI from html_string
- # html_string.slice(Gem::URI.regexp)
- #
- # # remove ftp URIs
- # html_string.sub(Gem::URI.regexp(['ftp']), '')
- #
- # # You should not rely on the number of parentheses
- # html_string.scan(Gem::URI.regexp) do |*matches|
- # p $&
- # end
- #
- def self.regexp(schemes = nil)# :nodoc:
- warn "Gem::URI.regexp is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.make_regexp(schemes)
- end
-
- TBLENCWWWCOMP_ = {} # :nodoc:
- 256.times do |i|
- TBLENCWWWCOMP_[-i.chr] = -('%%%02X' % i)
- end
- TBLENCURICOMP_ = TBLENCWWWCOMP_.dup.freeze
- TBLENCWWWCOMP_[' '] = '+'
- TBLENCWWWCOMP_.freeze
- TBLDECWWWCOMP_ = {} # :nodoc:
- 256.times do |i|
- h, l = i>>4, i&15
- TBLDECWWWCOMP_[-('%%%X%X' % [h, l])] = -i.chr
- TBLDECWWWCOMP_[-('%%%x%X' % [h, l])] = -i.chr
- TBLDECWWWCOMP_[-('%%%X%x' % [h, l])] = -i.chr
- TBLDECWWWCOMP_[-('%%%x%x' % [h, l])] = -i.chr
- end
- 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:
- #
- # Gem::URI.encode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
- #
- # - Converts:
- #
- # - 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>.
- #
- # Example:
- #
- # Gem::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: Gem::URI.encode_uri_component (encodes <tt>' '</tt> as <tt>'%20'</tt>).
- 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:
- #
- # Gem::URI.decode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
- #
- # - Converts:
- #
- # - Character <tt>'+'</tt> to character <tt>' '</tt>.
- # - Each "percent notation" to an ASCII character.
- #
- # Example:
- #
- # Gem::URI.decode_www_form_component('Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A')
- # # => "Here are some punctuation characters: ,;?:"
- #
- # Related: Gem::URI.decode_uri_component (preserves <tt>'+'</tt>).
- def self.decode_www_form_component(str, enc=Encoding::UTF_8)
- _decode_uri_component(/\+|%\h\h/, str, enc)
- end
-
- # Like Gem::URI.encode_www_form_component, except that <tt>' '</tt> (space)
- # is encoded as <tt>'%20'</tt> (instead of <tt>'+'</tt>).
- def self.encode_uri_component(str, enc=nil)
- _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc)
- end
-
- # Like Gem::URI.decode_www_form_component, except that <tt>'+'</tt> is preserved.
- def self.decode_uri_component(str, enc=Encoding::UTF_8)
- _decode_uri_component(/%\h\h/, str, enc)
- end
-
- def self._encode_uri_component(regexp, table, str, enc)
- str = str.to_s.dup
- if str.encoding != Encoding::ASCII_8BIT
- if enc && enc != Encoding::ASCII_8BIT
- str.encode!(Encoding::UTF_8, invalid: :replace, undef: :replace)
- str.encode!(enc, fallback: ->(x){"&##{x.ord};"})
- end
- str.force_encoding(Encoding::ASCII_8BIT)
- end
- str.gsub!(regexp, table)
- str.force_encoding(Encoding::US_ASCII)
- end
- private_class_method :_encode_uri_component
-
- def self._decode_uri_component(regexp, str, enc)
- raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/.match?(str)
- str.b.gsub(regexp, TBLDECWWWCOMP_).force_encoding(enc)
- 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:
- #
- # Gem::URI.encode_www_form([['foo', 0], ['bar', 1], ['baz', 2]])
- # # => "foo=0&bar=1&baz=2"
- # Gem::URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The returned string is formed using method Gem::URI.encode_www_form_component,
- # which converts certain characters:
- #
- # Gem::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 = Gem::URI.encode_www_form_component(ele[0], enc)
- # value = Gem::URI.encode_www_form_component(ele[1], enc)
- # "#{name}=#{value}"
- #
- # Examples:
- #
- # Gem::URI.encode_www_form([%w[foo bar], %w[baz bat bah]])
- # # => "foo=bar&baz=bat"
- # Gem::URI.encode_www_form([['foo', 0], ['bar', :baz, 'bat']])
- # # => "foo=0&bar=baz"
- #
- # - If +ele+ is an array of one element,
- # the field is formed from <tt>ele[0]</tt>:
- #
- # Gem::URI.encode_www_form_component(ele[0])
- #
- # Example:
- #
- # Gem::URI.encode_www_form([['foo'], [:bar], [0]])
- # # => "foo&bar&0"
- #
- # - Otherwise the field is formed from +ele+:
- #
- # Gem::URI.encode_www_form_component(ele)
- #
- # Example:
- #
- # Gem::URI.encode_www_form(['foo', :bar, 0])
- # # => "foo&bar&0"
- #
- # The elements of an Array-like +enum+ may be mixture:
- #
- # Gem::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 = Gem::URI.encode_www_form_component(key, enc)
- # value = Gem::URI.encode_www_form_component(ele, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # Gem::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 = Gem::URI.encode_www_form_component(key, enc)
- # value = Gem::URI.encode_www_form_component(value, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # Gem::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:
- #
- # Gem::URI.encode_www_form({foo: [0, 1], bar: 2})
- # # => "foo=0&foo=1&bar=2"
- #
- def self.encode_www_form(enum, enc=nil)
- enum.map do |k,v|
- if v.nil?
- encode_www_form_component(k, enc)
- elsif v.respond_to?(:to_ary)
- v.to_ary.map do |w|
- str = encode_www_form_component(k, enc)
- unless w.nil?
- str << '='
- str << encode_www_form_component(w, enc)
- end
- end.join('&')
- else
- str = encode_www_form_component(k, enc)
- str << '='
- str << encode_www_form_component(v, enc)
- end
- 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].
- #
- # A simple example:
- #
- # Gem::URI.decode_www_form('foo=0&bar=1&baz')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
- #
- # The returned strings have certain conversions,
- # similar to those performed in Gem::URI.decode_www_form_component:
- #
- # Gem::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:
- #
- # Gem::URI.decode_www_form('foo=0&&bar=1&&baz=2')
- # # => [["foo", "0"], ["", ""], ["bar", "1"], ["", ""], ["baz", "2"]]
- #
- # A different separator may be specified:
- #
- # Gem::URI.decode_www_form('foo=0--bar=1--baz', separator: '--')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
- #
- 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 = []
- return ary if str.empty?
- enc = Encoding.find(enc)
- str.b.each_line(separator) do |string|
- string.chomp!(separator)
- key, sep, val = string.partition('=')
- if isindex
- if sep.empty?
- val = key
- key = +''
- end
- isindex = false
- end
-
- if use__charset_ and key == '_charset_' and e = get_encoding(val)
- enc = e
- use__charset_ = false
- end
-
- key.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_)
- if val
- val.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_)
- else
- val = +''
- end
-
- ary << [key, val]
- end
- ary.each do |k, v|
- k.force_encoding(enc)
- k.scrub!
- v.force_encoding(enc)
- v.scrub!
- end
- ary
- end
-
- private
-=begin command for WEB_ENCODINGS_
- curl https://encoding.spec.whatwg.org/encodings.json|
- ruby -rjson -e 'H={}
- h={
- "shift_jis"=>"Windows-31J",
- "euc-jp"=>"cp51932",
- "iso-2022-jp"=>"cp50221",
- "x-mac-cyrillic"=>"macCyrillic",
- }
- JSON($<.read).map{|x|x["encodings"]}.flatten.each{|x|
- Encoding.find(n=h.fetch(n=x["name"].downcase,n))rescue next
- x["labels"].each{|y|H[y]=n}
- }
- puts "{"
- H.each{|k,v|puts %[ #{k.dump}=>#{v.dump},]}
- puts "}"
-'
-=end
- WEB_ENCODINGS_ = {
- "unicode-1-1-utf-8"=>"utf-8",
- "utf-8"=>"utf-8",
- "utf8"=>"utf-8",
- "866"=>"ibm866",
- "cp866"=>"ibm866",
- "csibm866"=>"ibm866",
- "ibm866"=>"ibm866",
- "csisolatin2"=>"iso-8859-2",
- "iso-8859-2"=>"iso-8859-2",
- "iso-ir-101"=>"iso-8859-2",
- "iso8859-2"=>"iso-8859-2",
- "iso88592"=>"iso-8859-2",
- "iso_8859-2"=>"iso-8859-2",
- "iso_8859-2:1987"=>"iso-8859-2",
- "l2"=>"iso-8859-2",
- "latin2"=>"iso-8859-2",
- "csisolatin3"=>"iso-8859-3",
- "iso-8859-3"=>"iso-8859-3",
- "iso-ir-109"=>"iso-8859-3",
- "iso8859-3"=>"iso-8859-3",
- "iso88593"=>"iso-8859-3",
- "iso_8859-3"=>"iso-8859-3",
- "iso_8859-3:1988"=>"iso-8859-3",
- "l3"=>"iso-8859-3",
- "latin3"=>"iso-8859-3",
- "csisolatin4"=>"iso-8859-4",
- "iso-8859-4"=>"iso-8859-4",
- "iso-ir-110"=>"iso-8859-4",
- "iso8859-4"=>"iso-8859-4",
- "iso88594"=>"iso-8859-4",
- "iso_8859-4"=>"iso-8859-4",
- "iso_8859-4:1988"=>"iso-8859-4",
- "l4"=>"iso-8859-4",
- "latin4"=>"iso-8859-4",
- "csisolatincyrillic"=>"iso-8859-5",
- "cyrillic"=>"iso-8859-5",
- "iso-8859-5"=>"iso-8859-5",
- "iso-ir-144"=>"iso-8859-5",
- "iso8859-5"=>"iso-8859-5",
- "iso88595"=>"iso-8859-5",
- "iso_8859-5"=>"iso-8859-5",
- "iso_8859-5:1988"=>"iso-8859-5",
- "arabic"=>"iso-8859-6",
- "asmo-708"=>"iso-8859-6",
- "csiso88596e"=>"iso-8859-6",
- "csiso88596i"=>"iso-8859-6",
- "csisolatinarabic"=>"iso-8859-6",
- "ecma-114"=>"iso-8859-6",
- "iso-8859-6"=>"iso-8859-6",
- "iso-8859-6-e"=>"iso-8859-6",
- "iso-8859-6-i"=>"iso-8859-6",
- "iso-ir-127"=>"iso-8859-6",
- "iso8859-6"=>"iso-8859-6",
- "iso88596"=>"iso-8859-6",
- "iso_8859-6"=>"iso-8859-6",
- "iso_8859-6:1987"=>"iso-8859-6",
- "csisolatingreek"=>"iso-8859-7",
- "ecma-118"=>"iso-8859-7",
- "elot_928"=>"iso-8859-7",
- "greek"=>"iso-8859-7",
- "greek8"=>"iso-8859-7",
- "iso-8859-7"=>"iso-8859-7",
- "iso-ir-126"=>"iso-8859-7",
- "iso8859-7"=>"iso-8859-7",
- "iso88597"=>"iso-8859-7",
- "iso_8859-7"=>"iso-8859-7",
- "iso_8859-7:1987"=>"iso-8859-7",
- "sun_eu_greek"=>"iso-8859-7",
- "csiso88598e"=>"iso-8859-8",
- "csisolatinhebrew"=>"iso-8859-8",
- "hebrew"=>"iso-8859-8",
- "iso-8859-8"=>"iso-8859-8",
- "iso-8859-8-e"=>"iso-8859-8",
- "iso-ir-138"=>"iso-8859-8",
- "iso8859-8"=>"iso-8859-8",
- "iso88598"=>"iso-8859-8",
- "iso_8859-8"=>"iso-8859-8",
- "iso_8859-8:1988"=>"iso-8859-8",
- "visual"=>"iso-8859-8",
- "csisolatin6"=>"iso-8859-10",
- "iso-8859-10"=>"iso-8859-10",
- "iso-ir-157"=>"iso-8859-10",
- "iso8859-10"=>"iso-8859-10",
- "iso885910"=>"iso-8859-10",
- "l6"=>"iso-8859-10",
- "latin6"=>"iso-8859-10",
- "iso-8859-13"=>"iso-8859-13",
- "iso8859-13"=>"iso-8859-13",
- "iso885913"=>"iso-8859-13",
- "iso-8859-14"=>"iso-8859-14",
- "iso8859-14"=>"iso-8859-14",
- "iso885914"=>"iso-8859-14",
- "csisolatin9"=>"iso-8859-15",
- "iso-8859-15"=>"iso-8859-15",
- "iso8859-15"=>"iso-8859-15",
- "iso885915"=>"iso-8859-15",
- "iso_8859-15"=>"iso-8859-15",
- "l9"=>"iso-8859-15",
- "iso-8859-16"=>"iso-8859-16",
- "cskoi8r"=>"koi8-r",
- "koi"=>"koi8-r",
- "koi8"=>"koi8-r",
- "koi8-r"=>"koi8-r",
- "koi8_r"=>"koi8-r",
- "koi8-ru"=>"koi8-u",
- "koi8-u"=>"koi8-u",
- "dos-874"=>"windows-874",
- "iso-8859-11"=>"windows-874",
- "iso8859-11"=>"windows-874",
- "iso885911"=>"windows-874",
- "tis-620"=>"windows-874",
- "windows-874"=>"windows-874",
- "cp1250"=>"windows-1250",
- "windows-1250"=>"windows-1250",
- "x-cp1250"=>"windows-1250",
- "cp1251"=>"windows-1251",
- "windows-1251"=>"windows-1251",
- "x-cp1251"=>"windows-1251",
- "ansi_x3.4-1968"=>"windows-1252",
- "ascii"=>"windows-1252",
- "cp1252"=>"windows-1252",
- "cp819"=>"windows-1252",
- "csisolatin1"=>"windows-1252",
- "ibm819"=>"windows-1252",
- "iso-8859-1"=>"windows-1252",
- "iso-ir-100"=>"windows-1252",
- "iso8859-1"=>"windows-1252",
- "iso88591"=>"windows-1252",
- "iso_8859-1"=>"windows-1252",
- "iso_8859-1:1987"=>"windows-1252",
- "l1"=>"windows-1252",
- "latin1"=>"windows-1252",
- "us-ascii"=>"windows-1252",
- "windows-1252"=>"windows-1252",
- "x-cp1252"=>"windows-1252",
- "cp1253"=>"windows-1253",
- "windows-1253"=>"windows-1253",
- "x-cp1253"=>"windows-1253",
- "cp1254"=>"windows-1254",
- "csisolatin5"=>"windows-1254",
- "iso-8859-9"=>"windows-1254",
- "iso-ir-148"=>"windows-1254",
- "iso8859-9"=>"windows-1254",
- "iso88599"=>"windows-1254",
- "iso_8859-9"=>"windows-1254",
- "iso_8859-9:1989"=>"windows-1254",
- "l5"=>"windows-1254",
- "latin5"=>"windows-1254",
- "windows-1254"=>"windows-1254",
- "x-cp1254"=>"windows-1254",
- "cp1255"=>"windows-1255",
- "windows-1255"=>"windows-1255",
- "x-cp1255"=>"windows-1255",
- "cp1256"=>"windows-1256",
- "windows-1256"=>"windows-1256",
- "x-cp1256"=>"windows-1256",
- "cp1257"=>"windows-1257",
- "windows-1257"=>"windows-1257",
- "x-cp1257"=>"windows-1257",
- "cp1258"=>"windows-1258",
- "windows-1258"=>"windows-1258",
- "x-cp1258"=>"windows-1258",
- "x-mac-cyrillic"=>"macCyrillic",
- "x-mac-ukrainian"=>"macCyrillic",
- "chinese"=>"gbk",
- "csgb2312"=>"gbk",
- "csiso58gb231280"=>"gbk",
- "gb2312"=>"gbk",
- "gb_2312"=>"gbk",
- "gb_2312-80"=>"gbk",
- "gbk"=>"gbk",
- "iso-ir-58"=>"gbk",
- "x-gbk"=>"gbk",
- "gb18030"=>"gb18030",
- "big5"=>"big5",
- "big5-hkscs"=>"big5",
- "cn-big5"=>"big5",
- "csbig5"=>"big5",
- "x-x-big5"=>"big5",
- "cseucpkdfmtjapanese"=>"cp51932",
- "euc-jp"=>"cp51932",
- "x-euc-jp"=>"cp51932",
- "csiso2022jp"=>"cp50221",
- "iso-2022-jp"=>"cp50221",
- "csshiftjis"=>"Windows-31J",
- "ms932"=>"Windows-31J",
- "ms_kanji"=>"Windows-31J",
- "shift-jis"=>"Windows-31J",
- "shift_jis"=>"Windows-31J",
- "sjis"=>"Windows-31J",
- "windows-31j"=>"Windows-31J",
- "x-sjis"=>"Windows-31J",
- "cseuckr"=>"euc-kr",
- "csksc56011987"=>"euc-kr",
- "euc-kr"=>"euc-kr",
- "iso-ir-149"=>"euc-kr",
- "korean"=>"euc-kr",
- "ks_c_5601-1987"=>"euc-kr",
- "ks_c_5601-1989"=>"euc-kr",
- "ksc5601"=>"euc-kr",
- "ksc_5601"=>"euc-kr",
- "windows-949"=>"euc-kr",
- "utf-16be"=>"utf-16be",
- "utf-16"=>"utf-16le",
- "utf-16le"=>"utf-16le",
- } # :nodoc:
- Ractor.make_shareable(WEB_ENCODINGS_) if defined?(Ractor)
-
- # :nodoc:
- # return encoding or nil
- # http://encoding.spec.whatwg.org/#concept-encoding-get
- def self.get_encoding(label)
- Encoding.find(WEB_ENCODINGS_[label.to_str.strip.downcase]) rescue nil
- end
-end # module Gem::URI
-
-module Gem
-
- #
- # Returns a \Gem::URI object derived from the given +uri+,
- # which may be a \Gem::URI string or an existing \Gem::URI object:
- #
- # # Returns a new Gem::URI.
- # uri = Gem::URI('http://github.com/ruby/ruby')
- # # => #<Gem::URI::HTTP http://github.com/ruby/ruby>
- # # Returns the given Gem::URI.
- # Gem::URI(uri)
- # # => #<Gem::URI::HTTP http://github.com/ruby/ruby>
- #
- def URI(uri)
- if uri.is_a?(Gem::URI::Generic)
- uri
- elsif uri = String.try_convert(uri)
- Gem::URI.parse(uri)
- else
- raise ArgumentError,
- "bad argument (expected Gem::URI object or Gem::URI string)"
- end
- end
- module_function :URI
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/file.rb b/lib/rubygems/vendor/uri/lib/uri/file.rb
deleted file mode 100644
index d419b26055..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/file.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # The "file" Gem::URI is defined by RFC8089.
- #
- class File < Generic
- # A Default port of nil for Gem::URI::File.
- DEFAULT_PORT = nil
-
- #
- # An Array of the available components for Gem::URI::File.
- #
- COMPONENT = [
- :scheme,
- :host,
- :path
- ].freeze
-
- #
- # == Description
- #
- # Creates a new Gem::URI::File object from components, with syntax checking.
- #
- # The components accepted are +host+ and +path+.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[host, path]</code>.
- #
- # A path from e.g. the File class should be escaped before
- # being passed.
- #
- # Examples:
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri1 = Gem::URI::File.build(['host.example.com', '/path/file.zip'])
- # uri1.to_s # => "file://host.example.com/path/file.zip"
- #
- # uri2 = Gem::URI::File.build({:host => 'host.example.com',
- # :path => '/ruby/src'})
- # uri2.to_s # => "file://host.example.com/ruby/src"
- #
- # uri3 = Gem::URI::File.build({:path => Gem::URI::escape('/path/my file.txt')})
- # uri3.to_s # => "file:///path/my%20file.txt"
- #
- def self.build(args)
- tmp = Util::make_components_hash(self, args)
- super(tmp)
- end
-
- # Protected setter for the host component +v+.
- #
- # See also Gem::URI::Generic.host=.
- #
- def set_host(v)
- v = "" if v.nil? || v == "localhost"
- @host = v
- end
-
- # do nothing
- def set_port(v)
- end
-
- # raise InvalidURIError
- def check_userinfo(user)
- raise Gem::URI::InvalidURIError, "can not set userinfo for file Gem::URI"
- end
-
- # raise InvalidURIError
- def check_user(user)
- raise Gem::URI::InvalidURIError, "can not set user for file Gem::URI"
- end
-
- # raise InvalidURIError
- def check_password(user)
- raise Gem::URI::InvalidURIError, "can not set password for file Gem::URI"
- end
-
- # do nothing
- def set_userinfo(v)
- end
-
- # do nothing
- def set_user(v)
- end
-
- # do nothing
- def set_password(v)
- end
- end
-
- register_scheme 'FILE', File
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/ftp.rb b/lib/rubygems/vendor/uri/lib/uri/ftp.rb
deleted file mode 100644
index 100498ffb2..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/ftp.rb
+++ /dev/null
@@ -1,267 +0,0 @@
-# frozen_string_literal: false
-# = uri/ftp.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # FTP Gem::URI syntax is defined by RFC1738 section 3.2.
- #
- # This class will be redesigned because of difference of implementations;
- # the structure of its path. draft-hoffman-ftp-uri-04 is a draft but it
- # is a good summary about the de facto spec.
- # http://tools.ietf.org/html/draft-hoffman-ftp-uri-04
- #
- class FTP < Generic
- # A Default port of 21 for Gem::URI::FTP.
- DEFAULT_PORT = 21
-
- #
- # An Array of the available components for Gem::URI::FTP.
- #
- COMPONENT = [
- :scheme,
- :userinfo, :host, :port,
- :path, :typecode
- ].freeze
-
- #
- # Typecode is "a", "i", or "d".
- #
- # * "a" indicates a text file (the FTP command was ASCII)
- # * "i" indicates a binary file (FTP command IMAGE)
- # * "d" indicates the contents of a directory should be displayed
- #
- TYPECODE = ['a', 'i', 'd'].freeze
-
- # Typecode prefix ";type=".
- TYPECODE_PREFIX = ';type='.freeze
-
- def self.new2(user, password, host, port, path,
- typecode = nil, arg_check = true) # :nodoc:
- # Do not use this method! Not tested. [Bug #7301]
- # This methods remains just for compatibility,
- # Keep it undocumented until the active maintainer is assigned.
- typecode = nil if typecode.size == 0
- if typecode && !TYPECODE.include?(typecode)
- raise ArgumentError,
- "bad typecode is specified: #{typecode}"
- end
-
- # do escape
-
- self.new('ftp',
- [user, password],
- host, port, nil,
- typecode ? path + TYPECODE_PREFIX + typecode : path,
- nil, nil, nil, arg_check)
- end
-
- #
- # == Description
- #
- # Creates a new Gem::URI::FTP object from components, with syntax checking.
- #
- # The components accepted are +userinfo+, +host+, +port+, +path+, and
- # +typecode+.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[userinfo, host, port, path, typecode]</code>.
- #
- # If the path supplied is absolute, it will be escaped in order to
- # make it absolute in the Gem::URI.
- #
- # Examples:
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri1 = Gem::URI::FTP.build(['user:password', 'ftp.example.com', nil,
- # '/path/file.zip', 'i'])
- # uri1.to_s # => "ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=i"
- #
- # uri2 = Gem::URI::FTP.build({:host => 'ftp.example.com',
- # :path => 'ruby/src'})
- # uri2.to_s # => "ftp://ftp.example.com/ruby/src"
- #
- def self.build(args)
-
- # Fix the incoming path to be generic URL syntax
- # FTP path -> URL path
- # foo/bar /foo/bar
- # /foo/bar /%2Ffoo/bar
- #
- if args.kind_of?(Array)
- args[3] = '/' + args[3].sub(/^\//, '%2F')
- else
- args[:path] = '/' + args[:path].sub(/^\//, '%2F')
- end
-
- tmp = Util::make_components_hash(self, args)
-
- if tmp[:typecode]
- if tmp[:typecode].size == 1
- tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode]
- end
- tmp[:path] << tmp[:typecode]
- end
-
- return super(tmp)
- end
-
- #
- # == Description
- #
- # Creates a new Gem::URI::FTP object from generic URL components with no
- # syntax checking.
- #
- # Unlike build(), this method does not escape the path component as
- # required by RFC1738; instead it is treated as per RFC2396.
- #
- # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
- # +opaque+, +query+, and +fragment+, in that order.
- #
- def initialize(scheme,
- userinfo, host, port, registry,
- path, opaque,
- query,
- fragment,
- parser = nil,
- arg_check = false)
- raise InvalidURIError unless path
- path = path.sub(/^\//,'')
- path.sub!(/^%2F/,'/')
- super(scheme, userinfo, host, port, registry, path, opaque,
- query, fragment, parser, arg_check)
- @typecode = nil
- if tmp = @path.index(TYPECODE_PREFIX)
- typecode = @path[tmp + TYPECODE_PREFIX.size..-1]
- @path = @path[0..tmp - 1]
-
- if arg_check
- self.typecode = typecode
- else
- self.set_typecode(typecode)
- end
- end
- end
-
- # typecode accessor.
- #
- # See Gem::URI::FTP::COMPONENT.
- attr_reader :typecode
-
- # Validates typecode +v+,
- # returns +true+ or +false+.
- #
- def check_typecode(v)
- if TYPECODE.include?(v)
- return true
- else
- raise InvalidComponentError,
- "bad typecode(expected #{TYPECODE.join(', ')}): #{v}"
- end
- end
- private :check_typecode
-
- # Private setter for the typecode +v+.
- #
- # See also Gem::URI::FTP.typecode=.
- #
- def set_typecode(v)
- @typecode = v
- end
- protected :set_typecode
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the typecode +v+
- # (with validation).
- #
- # See also Gem::URI::FTP.check_typecode.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("ftp://john@ftp.example.com/my_file.img")
- # #=> #<Gem::URI::FTP ftp://john@ftp.example.com/my_file.img>
- # uri.typecode = "i"
- # uri
- # #=> #<Gem::URI::FTP ftp://john@ftp.example.com/my_file.img;type=i>
- #
- def typecode=(typecode)
- check_typecode(typecode)
- set_typecode(typecode)
- typecode
- end
-
- def merge(oth) # :nodoc:
- tmp = super(oth)
- if self != tmp
- tmp.set_typecode(oth.typecode)
- end
-
- return tmp
- end
-
- # Returns the path from an FTP Gem::URI.
- #
- # RFC 1738 specifically states that the path for an FTP Gem::URI does not
- # include the / which separates the Gem::URI path from the Gem::URI host. Example:
- #
- # <code>ftp://ftp.example.com/pub/ruby</code>
- #
- # The above Gem::URI indicates that the client should connect to
- # ftp.example.com then cd to pub/ruby from the initial login directory.
- #
- # If you want to cd to an absolute directory, you must include an
- # escaped / (%2F) in the path. Example:
- #
- # <code>ftp://ftp.example.com/%2Fpub/ruby</code>
- #
- # This method will then return "/pub/ruby".
- #
- def path
- return @path.sub(/^\//,'').sub(/^%2F/,'/')
- end
-
- # Private setter for the path of the Gem::URI::FTP.
- def set_path(v)
- super("/" + v.sub(/^\//, "%2F"))
- end
- protected :set_path
-
- # Returns a String representation of the Gem::URI::FTP.
- def to_s
- save_path = nil
- if @typecode
- save_path = @path
- @path = @path + TYPECODE_PREFIX + @typecode
- end
- str = super
- if @typecode
- @path = save_path
- end
-
- return str
- end
- end
-
- register_scheme 'FTP', FTP
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/generic.rb b/lib/rubygems/vendor/uri/lib/uri/generic.rb
deleted file mode 100644
index 72c52aa8ee..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/generic.rb
+++ /dev/null
@@ -1,1588 +0,0 @@
-# frozen_string_literal: true
-
-# = uri/generic.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'common'
-autoload :IPSocket, 'socket'
-autoload :IPAddr, 'ipaddr'
-
-module Gem::URI
-
- #
- # Base class for all Gem::URI classes.
- # Implements generic Gem::URI syntax as per RFC 2396.
- #
- class Generic
- include Gem::URI
-
- #
- # A Default port of nil for Gem::URI::Generic.
- #
- DEFAULT_PORT = nil
-
- #
- # Returns default port.
- #
- def self.default_port
- self::DEFAULT_PORT
- end
-
- #
- # Returns default port.
- #
- def default_port
- self.class.default_port
- end
-
- #
- # An Array of the available components for Gem::URI::Generic.
- #
- COMPONENT = [
- :scheme,
- :userinfo, :host, :port, :registry,
- :path, :opaque,
- :query,
- :fragment
- ].freeze
-
- #
- # Components of the Gem::URI in the order.
- #
- def self.component
- self::COMPONENT
- end
-
- USE_REGISTRY = false # :nodoc:
-
- def self.use_registry # :nodoc:
- self::USE_REGISTRY
- end
-
- #
- # == Synopsis
- #
- # See ::new.
- #
- # == Description
- #
- # At first, tries to create a new Gem::URI::Generic instance using
- # Gem::URI::Generic::build. But, if exception Gem::URI::InvalidComponentError is raised,
- # then it does Gem::URI::Escape.escape all Gem::URI components and tries again.
- #
- def self.build2(args)
- begin
- return self.build(args)
- rescue InvalidComponentError
- if args.kind_of?(Array)
- return self.build(args.collect{|x|
- if x.is_a?(String)
- DEFAULT_PARSER.escape(x)
- else
- x
- end
- })
- elsif args.kind_of?(Hash)
- tmp = {}
- args.each do |key, value|
- tmp[key] = if value
- DEFAULT_PARSER.escape(value)
- else
- value
- end
- end
- return self.build(tmp)
- end
- end
- end
-
- #
- # == Synopsis
- #
- # See ::new.
- #
- # == Description
- #
- # Creates a new Gem::URI::Generic instance from components of Gem::URI::Generic
- # with check. Components are: scheme, userinfo, host, port, registry, path,
- # opaque, query, and fragment. You can provide arguments either by an Array or a Hash.
- # See ::new for hash keys to use or for order of array items.
- #
- def self.build(args)
- if args.kind_of?(Array) &&
- args.size == ::Gem::URI::Generic::COMPONENT.size
- tmp = args.dup
- elsif args.kind_of?(Hash)
- tmp = ::Gem::URI::Generic::COMPONENT.collect do |c|
- if args.include?(c)
- args[c]
- else
- nil
- end
- end
- else
- component = self.class.component rescue ::Gem::URI::Generic::COMPONENT
- raise ArgumentError,
- "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})"
- end
-
- tmp << nil
- tmp << true
- return self.new(*tmp)
- end
-
- #
- # == Args
- #
- # +scheme+::
- # Protocol scheme, i.e. 'http','ftp','mailto' and so on.
- # +userinfo+::
- # User name and password, i.e. 'sdmitry:bla'.
- # +host+::
- # Server host name.
- # +port+::
- # Server port.
- # +registry+::
- # Registry of naming authorities.
- # +path+::
- # Path on server.
- # +opaque+::
- # Opaque part.
- # +query+::
- # Query data.
- # +fragment+::
- # Part of the Gem::URI after '#' character.
- # +parser+::
- # Parser for internal use [Gem::URI::DEFAULT_PARSER by default].
- # +arg_check+::
- # Check arguments [false by default].
- #
- # == Description
- #
- # Creates a new Gem::URI::Generic instance from ``generic'' components without check.
- #
- def initialize(scheme,
- userinfo, host, port, registry,
- path, opaque,
- query,
- fragment,
- parser = DEFAULT_PARSER,
- arg_check = false)
- @scheme = nil
- @user = nil
- @password = nil
- @host = nil
- @port = nil
- @path = nil
- @query = nil
- @opaque = nil
- @fragment = nil
- @parser = parser == DEFAULT_PARSER ? nil : parser
-
- if arg_check
- self.scheme = scheme
- self.userinfo = userinfo
- self.hostname = host
- self.port = port
- self.path = path
- self.query = query
- self.opaque = opaque
- self.fragment = fragment
- else
- self.set_scheme(scheme)
- self.set_userinfo(userinfo)
- self.set_host(host)
- self.set_port(port)
- self.set_path(path)
- self.query = query
- self.set_opaque(opaque)
- self.fragment=(fragment)
- end
- if registry
- raise InvalidURIError,
- "the scheme #{@scheme} does not accept registry part: #{registry} (or bad hostname?)"
- end
-
- @scheme&.freeze
- self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2)
- self.set_port(self.default_port) if self.default_port && !@port
- end
-
- #
- # Returns the scheme component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz").scheme #=> "http"
- #
- attr_reader :scheme
-
- # Returns the host component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz").host #=> "foo"
- #
- # It returns nil if no host component exists.
- #
- # Gem::URI("mailto:foo@example.org").host #=> nil
- #
- # The component does not contain the port number.
- #
- # Gem::URI("http://foo:8080/bar/baz").host #=> "foo"
- #
- # Since IPv6 addresses are wrapped with brackets in URIs,
- # this method returns IPv6 addresses wrapped with brackets.
- # This form is not appropriate to pass to socket methods such as TCPSocket.open.
- # If unwrapped host names are required, use the #hostname method.
- #
- # Gem::URI("http://[::1]/bar/baz").host #=> "[::1]"
- # Gem::URI("http://[::1]/bar/baz").hostname #=> "::1"
- #
- attr_reader :host
-
- # Returns the port component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz").port #=> 80
- # Gem::URI("http://foo:8080/bar/baz").port #=> 8080
- #
- attr_reader :port
-
- def registry # :nodoc:
- nil
- end
-
- # Returns the path component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz").path #=> "/bar/baz"
- #
- attr_reader :path
-
- # Returns the query component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz?search=FooBar").query #=> "search=FooBar"
- #
- attr_reader :query
-
- # Returns the opaque part of the Gem::URI.
- #
- # Gem::URI("mailto:foo@example.org").opaque #=> "foo@example.org"
- # Gem::URI("http://foo/bar/baz").opaque #=> nil
- #
- # The portion of the path that does not make use of the slash '/'.
- # The path typically refers to an absolute path or an opaque part.
- # (See RFC2396 Section 3 and 5.2.)
- #
- attr_reader :opaque
-
- # Returns the fragment component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz?search=FooBar#ponies").fragment #=> "ponies"
- #
- attr_reader :fragment
-
- # Returns the parser to be used.
- #
- # Unless a Gem::URI::Parser is defined, DEFAULT_PARSER is used.
- #
- def parser
- if !defined?(@parser) || !@parser
- DEFAULT_PARSER
- else
- @parser || DEFAULT_PARSER
- end
- end
-
- # Replaces self by other Gem::URI object.
- #
- def replace!(oth)
- if self.class != oth.class
- raise ArgumentError, "expected #{self.class} object"
- end
-
- component.each do |c|
- self.__send__("#{c}=", oth.__send__(c))
- end
- end
- private :replace!
-
- #
- # Components of the Gem::URI in the order.
- #
- def component
- self.class.component
- end
-
- #
- # Checks the scheme +v+ component against the Gem::URI::Parser Regexp for :SCHEME.
- #
- def check_scheme(v)
- if v && parser.regexp[:SCHEME] !~ v
- raise InvalidComponentError,
- "bad component(expected scheme component): #{v}"
- end
-
- return true
- end
- private :check_scheme
-
- # Protected setter for the scheme component +v+.
- #
- # See also Gem::URI::Generic.scheme=.
- #
- def set_scheme(v)
- @scheme = v&.downcase
- end
- protected :set_scheme
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the scheme component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_scheme.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.scheme = "https"
- # uri.to_s #=> "https://my.example.com"
- #
- def scheme=(v)
- check_scheme(v)
- set_scheme(v)
- v
- end
-
- #
- # Checks the +user+ and +password+.
- #
- # If +password+ is not provided, then +user+ is
- # split, using Gem::URI::Generic.split_userinfo, to
- # pull +user+ and +password.
- #
- # See also Gem::URI::Generic.check_user, Gem::URI::Generic.check_password.
- #
- def check_userinfo(user, password = nil)
- if !password
- user, password = split_userinfo(user)
- end
- check_user(user)
- check_password(password, user)
-
- return true
- end
- private :check_userinfo
-
- #
- # Checks the user +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :USERINFO.
- #
- # Can not have a registry or opaque component defined,
- # with a user component defined.
- #
- def check_user(v)
- if @opaque
- raise InvalidURIError,
- "can not set user with opaque"
- end
-
- return v unless v
-
- if parser.regexp[:USERINFO] !~ v
- raise InvalidComponentError,
- "bad component(expected userinfo component or user component): #{v}"
- end
-
- return true
- end
- private :check_user
-
- #
- # Checks the password +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :USERINFO.
- #
- # Can not have a registry or opaque component defined,
- # with a user component defined.
- #
- def check_password(v, user = @user)
- if @opaque
- raise InvalidURIError,
- "can not set password with opaque"
- end
- return v unless v
-
- if !user
- raise InvalidURIError,
- "password component depends user component"
- end
-
- if parser.regexp[:USERINFO] !~ v
- raise InvalidComponentError,
- "bad password component"
- end
-
- return true
- end
- private :check_password
-
- #
- # Sets userinfo, argument is string like 'name:pass'.
- #
- def userinfo=(userinfo)
- if userinfo.nil?
- return nil
- end
- check_userinfo(*userinfo)
- set_userinfo(*userinfo)
- # returns userinfo
- end
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the +user+ component
- # (with validation).
- #
- # See also Gem::URI::Generic.check_user.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://john:S3nsit1ve@my.example.com")
- # uri.user = "sam"
- # uri.to_s #=> "http://sam:V3ry_S3nsit1ve@my.example.com"
- #
- def user=(user)
- check_user(user)
- set_user(user)
- # returns user
- end
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the +password+ component
- # (with validation).
- #
- # See also Gem::URI::Generic.check_password.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://john:S3nsit1ve@my.example.com")
- # uri.password = "V3ry_S3nsit1ve"
- # uri.to_s #=> "http://john:V3ry_S3nsit1ve@my.example.com"
- #
- def password=(password)
- check_password(password)
- set_password(password)
- # returns password
- end
-
- # Protected setter for the +user+ component, and +password+ if available
- # (with validation).
- #
- # See also Gem::URI::Generic.userinfo=.
- #
- def set_userinfo(user, password = nil)
- unless password
- user, password = split_userinfo(user)
- end
- @user = user
- @password = password if password
-
- [@user, @password]
- end
- protected :set_userinfo
-
- # Protected setter for the user component +v+.
- #
- # See also Gem::URI::Generic.user=.
- #
- def set_user(v)
- set_userinfo(v, @password)
- v
- end
- protected :set_user
-
- # Protected setter for the password component +v+.
- #
- # See also Gem::URI::Generic.password=.
- #
- def set_password(v)
- @password = v
- # returns v
- end
- protected :set_password
-
- # Returns the userinfo +ui+ as <code>[user, password]</code>
- # if properly formatted as 'user:password'.
- def split_userinfo(ui)
- return nil, nil unless ui
- user, password = ui.split(':', 2)
-
- return user, password
- end
- private :split_userinfo
-
- # Escapes 'user:password' +v+ based on RFC 1738 section 3.1.
- def escape_userpass(v)
- parser.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
- end
- private :escape_userpass
-
- # Returns the userinfo, either as 'user' or 'user:password'.
- def userinfo
- if @user.nil?
- nil
- elsif @password.nil?
- @user
- else
- @user + ':' + @password
- end
- end
-
- # Returns the user component (without Gem::URI decoding).
- def user
- @user
- end
-
- # Returns the password component (without Gem::URI decoding).
- def password
- @password
- end
-
- # Returns the user component after Gem::URI decoding.
- def decoded_user
- Gem::URI.decode_uri_component(@user) if @user
- end
-
- # Returns the password component after Gem::URI decoding.
- def decoded_password
- Gem::URI.decode_uri_component(@password) if @password
- end
-
- #
- # Checks the host +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :HOST.
- #
- # Can not have a registry or opaque component defined,
- # with a host component defined.
- #
- def check_host(v)
- return v unless v
-
- if @opaque
- raise InvalidURIError,
- "can not set host with registry or opaque"
- elsif parser.regexp[:HOST] !~ v
- raise InvalidComponentError,
- "bad component(expected host component): #{v}"
- end
-
- return true
- end
- private :check_host
-
- # Protected setter for the host component +v+.
- #
- # See also Gem::URI::Generic.host=.
- #
- def set_host(v)
- @host = v
- end
- protected :set_host
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the host component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_host.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.host = "foo.com"
- # uri.to_s #=> "http://foo.com"
- #
- def host=(v)
- check_host(v)
- set_host(v)
- v
- end
-
- # Extract the host part of the Gem::URI and unwrap brackets for IPv6 addresses.
- #
- # This method is the same as Gem::URI::Generic#host except
- # brackets for IPv6 (and future IP) addresses are removed.
- #
- # uri = Gem::URI("http://[::1]/bar")
- # uri.hostname #=> "::1"
- # uri.host #=> "[::1]"
- #
- def hostname
- v = self.host
- v&.start_with?('[') && v.end_with?(']') ? v[1..-2] : v
- end
-
- # Sets the host part of the Gem::URI as the argument with brackets for IPv6 addresses.
- #
- # This method is the same as Gem::URI::Generic#host= except
- # the argument can be a bare IPv6 address.
- #
- # uri = Gem::URI("http://foo/bar")
- # uri.hostname = "::1"
- # uri.to_s #=> "http://[::1]/bar"
- #
- # If the argument seems to be an IPv6 address,
- # it is wrapped with brackets.
- #
- def hostname=(v)
- v = "[#{v}]" if !(v&.start_with?('[') && v&.end_with?(']')) && v&.index(':')
- self.host = v
- end
-
- #
- # Checks the port +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :PORT.
- #
- # Can not have a registry or opaque component defined,
- # with a port component defined.
- #
- def check_port(v)
- return v unless v
-
- if @opaque
- raise InvalidURIError,
- "can not set port with registry or opaque"
- elsif !v.kind_of?(Integer) && parser.regexp[:PORT] !~ v
- raise InvalidComponentError,
- "bad component(expected port component): #{v.inspect}"
- end
-
- return true
- end
- private :check_port
-
- # Protected setter for the port component +v+.
- #
- # See also Gem::URI::Generic.port=.
- #
- def set_port(v)
- v = v.empty? ? nil : v.to_i unless !v || v.kind_of?(Integer)
- @port = v
- end
- protected :set_port
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the port component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_port.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.port = 8080
- # uri.to_s #=> "http://my.example.com:8080"
- #
- def port=(v)
- check_port(v)
- set_port(v)
- port
- end
-
- def check_registry(v) # :nodoc:
- raise InvalidURIError, "can not set registry"
- end
- private :check_registry
-
- def set_registry(v) #:nodoc:
- raise InvalidURIError, "can not set registry"
- end
- protected :set_registry
-
- def registry=(v)
- raise InvalidURIError, "can not set registry"
- end
-
- #
- # Checks the path +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp
- # for :ABS_PATH and :REL_PATH.
- #
- # Can not have a opaque component defined,
- # with a path component defined.
- #
- def check_path(v)
- # raise if both hier and opaque are not nil, because:
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
- # hier_part = ( net_path | abs_path ) [ "?" query ]
- if v && @opaque
- raise InvalidURIError,
- "path conflicts with opaque"
- end
-
- # If scheme is ftp, path may be relative.
- # See RFC 1738 section 3.2.2, and RFC 2396.
- if @scheme && @scheme != "ftp"
- if v && v != '' && parser.regexp[:ABS_PATH] !~ v
- raise InvalidComponentError,
- "bad component(expected absolute path component): #{v}"
- end
- else
- if v && v != '' && parser.regexp[:ABS_PATH] !~ v &&
- parser.regexp[:REL_PATH] !~ v
- raise InvalidComponentError,
- "bad component(expected relative path component): #{v}"
- end
- end
-
- return true
- end
- private :check_path
-
- # Protected setter for the path component +v+.
- #
- # See also Gem::URI::Generic.path=.
- #
- def set_path(v)
- @path = v
- end
- protected :set_path
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the path component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_path.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com/pub/files")
- # uri.path = "/faq/"
- # uri.to_s #=> "http://my.example.com/faq/"
- #
- def path=(v)
- check_path(v)
- set_path(v)
- v
- end
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the query component +v+.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com/?id=25")
- # uri.query = "id=1"
- # uri.to_s #=> "http://my.example.com/?id=1"
- #
- def query=(v)
- return @query = nil unless v
- raise InvalidURIError, "query conflicts with opaque" if @opaque
-
- x = v.to_str
- v = x.dup if x.equal? v
- v.encode!(Encoding::UTF_8) rescue nil
- v.delete!("\t\r\n")
- v.force_encoding(Encoding::ASCII_8BIT)
- raise InvalidURIError, "invalid percent escape: #{$1}" if /(%\H\H)/n.match(v)
- v.gsub!(/(?!%\h\h|[!$-&(-;=?-_a-~])./n.freeze){'%%%02X' % $&.ord}
- v.force_encoding(Encoding::US_ASCII)
- @query = v
- end
-
- #
- # Checks the opaque +v+ component for RFC2396 compliance and
- # against the Gem::URI::Parser Regexp for :OPAQUE.
- #
- # Can not have a host, port, user, or path component defined,
- # with an opaque component defined.
- #
- def check_opaque(v)
- return v unless v
-
- # raise if both hier and opaque are not nil, because:
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
- # hier_part = ( net_path | abs_path ) [ "?" query ]
- if @host || @port || @user || @path # userinfo = @user + ':' + @password
- raise InvalidURIError,
- "can not set opaque with host, port, userinfo or path"
- elsif v && parser.regexp[:OPAQUE] !~ v
- raise InvalidComponentError,
- "bad component(expected opaque component): #{v}"
- end
-
- return true
- end
- private :check_opaque
-
- # Protected setter for the opaque component +v+.
- #
- # See also Gem::URI::Generic.opaque=.
- #
- def set_opaque(v)
- @opaque = v
- end
- protected :set_opaque
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the opaque component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_opaque.
- #
- def opaque=(v)
- check_opaque(v)
- set_opaque(v)
- v
- end
-
- #
- # Checks the fragment +v+ component against the Gem::URI::Parser Regexp for :FRAGMENT.
- #
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the fragment component +v+
- # (with validation).
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com/?id=25#time=1305212049")
- # uri.fragment = "time=1305212086"
- # uri.to_s #=> "http://my.example.com/?id=25#time=1305212086"
- #
- def fragment=(v)
- return @fragment = nil unless v
-
- x = v.to_str
- v = x.dup if x.equal? v
- v.encode!(Encoding::UTF_8) rescue nil
- v.delete!("\t\r\n")
- v.force_encoding(Encoding::ASCII_8BIT)
- v.gsub!(/(?!%\h\h|[!-~])./n){'%%%02X' % $&.ord}
- v.force_encoding(Encoding::US_ASCII)
- @fragment = v
- end
-
- #
- # Returns true if Gem::URI is hierarchical.
- #
- # == Description
- #
- # Gem::URI has components listed in order of decreasing significance from left to right,
- # see RFC3986 https://tools.ietf.org/html/rfc3986 1.2.3.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com/")
- # uri.hierarchical?
- # #=> true
- # uri = Gem::URI.parse("mailto:joe@example.com")
- # uri.hierarchical?
- # #=> false
- #
- def hierarchical?
- if @path
- true
- else
- false
- end
- end
-
- #
- # Returns true if Gem::URI has a scheme (e.g. http:// or https://) specified.
- #
- def absolute?
- if @scheme
- true
- else
- false
- end
- end
- alias absolute absolute?
-
- #
- # Returns true if Gem::URI does not have a scheme (e.g. http:// or https://) specified.
- #
- def relative?
- !absolute?
- end
-
- #
- # Returns an Array of the path split on '/'.
- #
- def split_path(path)
- path.split("/", -1)
- end
- private :split_path
-
- #
- # Merges a base path +base+, with relative path +rel+,
- # returns a modified base path.
- #
- def merge_path(base, rel)
-
- # RFC2396, Section 5.2, 5)
- # RFC2396, Section 5.2, 6)
- base_path = split_path(base)
- rel_path = split_path(rel)
-
- # RFC2396, Section 5.2, 6), a)
- base_path << '' if base_path.last == '..'
- while i = base_path.index('..')
- base_path.slice!(i - 1, 2)
- end
-
- if (first = rel_path.first) and first.empty?
- base_path.clear
- rel_path.shift
- end
-
- # RFC2396, Section 5.2, 6), c)
- # RFC2396, Section 5.2, 6), d)
- rel_path.push('') if rel_path.last == '.' || rel_path.last == '..'
- rel_path.delete('.')
-
- # RFC2396, Section 5.2, 6), e)
- tmp = []
- rel_path.each do |x|
- if x == '..' &&
- !(tmp.empty? || tmp.last == '..')
- tmp.pop
- else
- tmp << x
- end
- end
-
- add_trailer_slash = !tmp.empty?
- if base_path.empty?
- base_path = [''] # keep '/' for root directory
- elsif add_trailer_slash
- base_path.pop
- end
- while x = tmp.shift
- if x == '..'
- # RFC2396, Section 4
- # a .. or . in an absolute path has no special meaning
- base_path.pop if base_path.size > 1
- else
- # if x == '..'
- # valid absolute (but abnormal) path "/../..."
- # else
- # valid absolute path
- # end
- base_path << x
- tmp.each {|t| base_path << t}
- add_trailer_slash = false
- break
- end
- end
- base_path.push('') if add_trailer_slash
-
- return base_path.join('/')
- end
- private :merge_path
-
- #
- # == Args
- #
- # +oth+::
- # Gem::URI or String
- #
- # == Description
- #
- # Destructive form of #merge.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.merge!("/main.rbx?page=1")
- # uri.to_s # => "http://my.example.com/main.rbx?page=1"
- #
- def merge!(oth)
- t = merge(oth)
- if self == t
- nil
- else
- replace!(t)
- self
- end
- end
-
- #
- # == Args
- #
- # +oth+::
- # Gem::URI or String
- #
- # == Description
- #
- # Merges two URIs.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.merge("/main.rbx?page=1")
- # # => "http://my.example.com/main.rbx?page=1"
- #
- def merge(oth)
- rel = parser.__send__(:convert_to_uri, oth)
-
- if rel.absolute?
- #raise BadURIError, "both Gem::URI are absolute" if absolute?
- # hmm... should return oth for usability?
- return rel
- end
-
- unless self.absolute?
- raise BadURIError, "both Gem::URI are relative"
- end
-
- base = self.dup
-
- authority = rel.userinfo || rel.host || rel.port
-
- # RFC2396, Section 5.2, 2)
- if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
- base.fragment=(rel.fragment) if rel.fragment
- return base
- end
-
- base.query = nil
- 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
- 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
-
- return base
- end # merge
- alias + merge
-
- # :stopdoc:
- def route_from_path(src, dst)
- case dst
- when src
- # RFC2396, Section 4.2
- return ''
- when %r{(?:\A|/)\.\.?(?:/|\z)}
- # dst has abnormal absolute path,
- # like "/./", "/../", "/x/../", ...
- return dst.dup
- end
-
- src_path = src.scan(%r{[^/]*/})
- dst_path = dst.scan(%r{[^/]*/?})
-
- # discard same parts
- while !dst_path.empty? && dst_path.first == src_path.first
- src_path.shift
- dst_path.shift
- end
-
- tmp = dst_path.join
-
- # calculate
- if src_path.empty?
- if tmp.empty?
- return './'
- elsif dst_path.first.include?(':') # (see RFC2396 Section 5)
- return './' + tmp
- else
- return tmp
- end
- end
-
- return '../' * src_path.size + tmp
- end
- private :route_from_path
- # :startdoc:
-
- # :stopdoc:
- def route_from0(oth)
- oth = parser.__send__(:convert_to_uri, oth)
- if self.relative?
- raise BadURIError,
- "relative Gem::URI: #{self}"
- end
- if oth.relative?
- raise BadURIError,
- "relative Gem::URI: #{oth}"
- end
-
- if self.scheme != oth.scheme
- return self, self.dup
- end
- rel = Gem::URI::Generic.new(nil, # it is relative Gem::URI
- self.userinfo, self.host, self.port,
- nil, self.path, self.opaque,
- self.query, self.fragment, parser)
-
- if rel.userinfo != oth.userinfo ||
- rel.host.to_s.downcase != oth.host.to_s.downcase ||
- rel.port != oth.port
-
- if self.userinfo.nil? && self.host.nil?
- return self, self.dup
- end
-
- rel.set_port(nil) if rel.port == oth.default_port
- return rel, rel
- end
- rel.set_userinfo(nil)
- rel.set_host(nil)
- rel.set_port(nil)
-
- if rel.path && rel.path == oth.path
- rel.set_path('')
- rel.query = nil if rel.query == oth.query
- return rel, rel
- elsif rel.opaque && rel.opaque == oth.opaque
- rel.set_opaque('')
- rel.query = nil if rel.query == oth.query
- return rel, rel
- end
-
- # you can modify `rel', but can not `oth'.
- return oth, rel
- end
- private :route_from0
- # :startdoc:
-
- #
- # == Args
- #
- # +oth+::
- # Gem::URI or String
- #
- # == Description
- #
- # Calculates relative path from oth to self.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse('http://my.example.com/main.rbx?page=1')
- # uri.route_from('http://my.example.com')
- # #=> #<Gem::URI::Generic /main.rbx?page=1>
- #
- def route_from(oth)
- # you can modify `rel', but can not `oth'.
- begin
- oth, rel = route_from0(oth)
- rescue
- raise $!.class, $!.message
- end
- if oth == rel
- return rel
- end
-
- rel.set_path(route_from_path(oth.path, self.path))
- if rel.path == './' && self.query
- # "./?foo" -> "?foo"
- rel.set_path('')
- end
-
- return rel
- end
-
- alias - route_from
-
- #
- # == Args
- #
- # +oth+::
- # Gem::URI or String
- #
- # == Description
- #
- # Calculates relative path to oth from self.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse('http://my.example.com')
- # uri.route_to('http://my.example.com/main.rbx?page=1')
- # #=> #<Gem::URI::Generic /main.rbx?page=1>
- #
- def route_to(oth)
- parser.__send__(:convert_to_uri, oth).route_from(self)
- end
-
- #
- # Returns normalized Gem::URI.
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # Gem::URI("HTTP://my.EXAMPLE.com").normalize
- # #=> #<Gem::URI::HTTP http://my.example.com/>
- #
- # Normalization here means:
- #
- # * scheme and host are converted to lowercase,
- # * an empty path component is set to "/".
- #
- def normalize
- uri = dup
- uri.normalize!
- uri
- end
-
- #
- # Destructive version of #normalize.
- #
- def normalize!
- if path&.empty?
- set_path('/')
- end
- if scheme && scheme != scheme.downcase
- set_scheme(self.scheme.downcase)
- end
- if host && host != host.downcase
- set_host(self.host.downcase)
- end
- end
-
- #
- # Constructs String from Gem::URI.
- #
- def to_s
- str = ''.dup
- if @scheme
- str << @scheme
- str << ':'
- end
-
- if @opaque
- str << @opaque
- else
- if @host || %w[file postgres].include?(@scheme)
- str << '//'
- end
- if self.userinfo
- str << self.userinfo
- str << '@'
- end
- if @host
- str << @host
- end
- if @port && @port != self.default_port
- str << ':'
- str << @port.to_s
- end
- str << @path
- if @query
- str << '?'
- str << @query
- end
- end
- if @fragment
- str << '#'
- str << @fragment
- end
- str
- end
- alias to_str to_s
-
- #
- # Compares two URIs.
- #
- def ==(oth)
- if self.class == oth.class
- self.normalize.component_ary == oth.normalize.component_ary
- else
- false
- end
- end
-
- def hash
- self.component_ary.hash
- end
-
- def eql?(oth)
- self.class == oth.class &&
- parser == oth.parser &&
- self.component_ary.eql?(oth.component_ary)
- end
-
-=begin
-
---- Gem::URI::Generic#===(oth)
-
-=end
-# def ===(oth)
-# raise NotImplementedError
-# end
-
-=begin
-=end
-
-
- # Returns an Array of the components defined from the COMPONENT Array.
- def component_ary
- component.collect do |x|
- self.__send__(x)
- end
- end
- protected :component_ary
-
- # == Args
- #
- # +components+::
- # Multiple Symbol arguments defined in Gem::URI::HTTP.
- #
- # == Description
- #
- # Selects specified components from Gem::URI.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse('http://myuser:mypass@my.example.com/test.rbx')
- # uri.select(:userinfo, :host, :path)
- # # => ["myuser:mypass", "my.example.com", "/test.rbx"]
- #
- def select(*components)
- components.collect do |c|
- if component.include?(c)
- self.__send__(c)
- else
- raise ArgumentError,
- "expected of components of #{self.class} (#{self.class.component.join(', ')})"
- end
- end
- end
-
- def inspect
- "#<#{self.class} #{self}>"
- end
-
- #
- # == Args
- #
- # +v+::
- # Gem::URI or String
- #
- # == Description
- #
- # Attempts to parse other Gem::URI +oth+,
- # returns [parsed_oth, self].
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.coerce("http://foo.com")
- # #=> [#<Gem::URI::HTTP http://foo.com>, #<Gem::URI::HTTP http://my.example.com>]
- #
- def coerce(oth)
- case oth
- when String
- oth = parser.parse(oth)
- else
- super
- end
-
- return oth, self
- end
-
- # Returns a proxy Gem::URI.
- # The proxy Gem::URI is obtained from environment variables such as http_proxy,
- # ftp_proxy, no_proxy, etc.
- # If there is no proper proxy, nil is returned.
- #
- # If the optional parameter +env+ is specified, it is used instead of ENV.
- #
- # Note that capitalized variables (HTTP_PROXY, FTP_PROXY, NO_PROXY, etc.)
- # are examined, too.
- #
- # But http_proxy and HTTP_PROXY is treated specially under CGI environment.
- # It's because HTTP_PROXY may be set by Proxy: header.
- # So HTTP_PROXY is not used.
- # http_proxy is not used too if the variable is case insensitive.
- # CGI_HTTP_PROXY can be used instead.
- def find_proxy(env=ENV)
- raise BadURIError, "relative Gem::URI: #{self}" if self.relative?
- name = self.scheme.downcase + '_proxy'
- proxy_uri = nil
- if name == 'http_proxy' && env.include?('REQUEST_METHOD') # CGI?
- # HTTP_PROXY conflicts with *_proxy for proxy settings and
- # HTTP_* for header information in CGI.
- # So it should be careful to use it.
- pairs = env.reject {|k, v| /\Ahttp_proxy\z/i !~ k }
- case pairs.length
- when 0 # no proxy setting anyway.
- proxy_uri = nil
- when 1
- k, _ = pairs.shift
- if k == 'http_proxy' && env[k.upcase] == nil
- # http_proxy is safe to use because ENV is case sensitive.
- proxy_uri = env[name]
- else
- proxy_uri = nil
- end
- else # http_proxy is safe to use because ENV is case sensitive.
- proxy_uri = env.to_hash[name]
- end
- if !proxy_uri
- # Use CGI_HTTP_PROXY. cf. libwww-perl.
- proxy_uri = env["CGI_#{name.upcase}"]
- end
- elsif name == 'http_proxy'
- if RUBY_ENGINE == 'jruby' && p_addr = ENV_JAVA['http.proxyHost']
- p_port = ENV_JAVA['http.proxyPort']
- if p_user = ENV_JAVA['http.proxyUser']
- p_pass = ENV_JAVA['http.proxyPass']
- proxy_uri = "http://#{p_user}:#{p_pass}@#{p_addr}:#{p_port}"
- else
- proxy_uri = "http://#{p_addr}:#{p_port}"
- end
- else
- unless proxy_uri = env[name]
- if proxy_uri = env[name.upcase]
- warn 'The environment variable HTTP_PROXY is discouraged. Use http_proxy.', uplevel: 1
- end
- end
- end
- else
- proxy_uri = env[name] || env[name.upcase]
- end
-
- if proxy_uri.nil? || proxy_uri.empty?
- return nil
- end
-
- if self.hostname
- begin
- addr = IPSocket.getaddress(self.hostname)
- return nil if /\A127\.|\A::1\z/ =~ addr
- rescue SocketError
- end
- end
-
- name = 'no_proxy'
- if no_proxy = env[name] || env[name.upcase]
- return nil unless Gem::URI::Generic.use_proxy?(self.hostname, addr, self.port, no_proxy)
- end
- Gem::URI.parse(proxy_uri)
- end
-
- def self.use_proxy?(hostname, addr, port, no_proxy) # :nodoc:
- hostname = hostname.downcase
- dothostname = ".#{hostname}"
- no_proxy.scan(/([^:,\s]+)(?::(\d+))?/) {|p_host, p_port|
- if !p_port || port == p_port.to_i
- if p_host.start_with?('.')
- return false if hostname.end_with?(p_host.downcase)
- else
- return false if dothostname.end_with?(".#{p_host.downcase}")
- end
- if addr
- begin
- return false if IPAddr.new(p_host).include?(addr)
- rescue IPAddr::InvalidAddressError
- next
- end
- end
- end
- }
- true
- end
- end
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/http.rb b/lib/rubygems/vendor/uri/lib/uri/http.rb
deleted file mode 100644
index bef43490a3..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/http.rb
+++ /dev/null
@@ -1,125 +0,0 @@
-# frozen_string_literal: false
-# = uri/http.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # The syntax of HTTP URIs is defined in RFC1738 section 3.3.
- #
- # Note that the Ruby Gem::URI library allows HTTP URLs containing usernames and
- # passwords. This is not legal as per the RFC, but used to be
- # supported in Internet Explorer 5 and 6, before the MS04-004 security
- # update. See <URL:http://support.microsoft.com/kb/834489>.
- #
- class HTTP < Generic
- # A Default port of 80 for Gem::URI::HTTP.
- DEFAULT_PORT = 80
-
- # An Array of the available components for Gem::URI::HTTP.
- COMPONENT = %i[
- scheme
- userinfo host port
- path
- query
- fragment
- ].freeze
-
- #
- # == Description
- #
- # Creates a new Gem::URI::HTTP object from components, with syntax checking.
- #
- # The components accepted are userinfo, host, port, path, query, and
- # fragment.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[userinfo, host, port, path, query, fragment]</code>.
- #
- # Example:
- #
- # uri = Gem::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar')
- #
- # uri = Gem::URI::HTTP.build([nil, "www.example.com", nil, "/path",
- # "query", 'fragment'])
- #
- # Currently, if passed userinfo components this method generates
- # invalid HTTP URIs as per RFC 1738.
- #
- def self.build(args)
- tmp = Util.make_components_hash(self, args)
- super(tmp)
- end
-
- #
- # == Description
- #
- # Returns the full path for an HTTP request, as required by Net::HTTP::Get.
- #
- # If the Gem::URI contains a query, the full path is Gem::URI#path + '?' + Gem::URI#query.
- # Otherwise, the path is simply Gem::URI#path.
- #
- # Example:
- #
- # uri = Gem::URI::HTTP.build(path: '/foo/bar', query: 'test=true')
- # uri.request_uri # => "/foo/bar?test=true"
- #
- def request_uri
- return unless @path
-
- url = @query ? "#@path?#@query" : @path.dup
- url.start_with?(?/.freeze) ? url : ?/ + url
- end
-
- #
- # == Description
- #
- # Returns the authority for an HTTP uri, as defined in
- # https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.
- #
- #
- # Example:
- #
- # Gem::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar').authority #=> "www.example.com"
- # Gem::URI::HTTP.build(host: 'www.example.com', port: 8000, path: '/foo/bar').authority #=> "www.example.com:8000"
- # Gem::URI::HTTP.build(host: 'www.example.com', port: 80, path: '/foo/bar').authority #=> "www.example.com"
- #
- def authority
- if port == default_port
- host
- else
- "#{host}:#{port}"
- end
- end
-
- #
- # == Description
- #
- # Returns the origin for an HTTP uri, as defined in
- # https://datatracker.ietf.org/doc/html/rfc6454.
- #
- #
- # Example:
- #
- # Gem::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar').origin #=> "http://www.example.com"
- # Gem::URI::HTTP.build(host: 'www.example.com', port: 8000, path: '/foo/bar').origin #=> "http://www.example.com:8000"
- # Gem::URI::HTTP.build(host: 'www.example.com', port: 80, path: '/foo/bar').origin #=> "http://www.example.com"
- # Gem::URI::HTTPS.build(host: 'www.example.com', path: '/foo/bar').origin #=> "https://www.example.com"
- #
- def origin
- "#{scheme}://#{authority}"
- end
- end
-
- register_scheme 'HTTP', HTTP
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/https.rb b/lib/rubygems/vendor/uri/lib/uri/https.rb
deleted file mode 100644
index 6e8e732e1d..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/https.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: false
-# = uri/https.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'http'
-
-module Gem::URI
-
- # The default port for HTTPS URIs is 443, and the scheme is 'https:' rather
- # than 'http:'. Other than that, HTTPS URIs are identical to HTTP URIs;
- # see Gem::URI::HTTP.
- class HTTPS < HTTP
- # A Default port of 443 for Gem::URI::HTTPS
- DEFAULT_PORT = 443
- end
-
- register_scheme 'HTTPS', HTTPS
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/ldap.rb b/lib/rubygems/vendor/uri/lib/uri/ldap.rb
deleted file mode 100644
index 1a08b5ab7e..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/ldap.rb
+++ /dev/null
@@ -1,261 +0,0 @@
-# frozen_string_literal: false
-# = uri/ldap.rb
-#
-# Author::
-# Takaaki Tateishi <ttate@jaist.ac.jp>
-# Akira Yamada <akira@ruby-lang.org>
-# License::
-# Gem::URI::LDAP is copyrighted free software by Takaaki Tateishi and Akira Yamada.
-# You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # LDAP Gem::URI SCHEMA (described in RFC2255).
- #--
- # ldap://<host>/<dn>[?<attrs>[?<scope>[?<filter>[?<extensions>]]]]
- #++
- class LDAP < Generic
-
- # A Default port of 389 for Gem::URI::LDAP.
- DEFAULT_PORT = 389
-
- # An Array of the available components for Gem::URI::LDAP.
- COMPONENT = [
- :scheme,
- :host, :port,
- :dn,
- :attributes,
- :scope,
- :filter,
- :extensions,
- ].freeze
-
- # Scopes available for the starting point.
- #
- # * SCOPE_BASE - the Base DN
- # * SCOPE_ONE - one level under the Base DN, not including the base DN and
- # not including any entries under this
- # * SCOPE_SUB - subtrees, all entries at all levels
- #
- SCOPE = [
- SCOPE_ONE = 'one',
- SCOPE_SUB = 'sub',
- SCOPE_BASE = 'base',
- ].freeze
-
- #
- # == Description
- #
- # Creates a new Gem::URI::LDAP object from components, with syntax checking.
- #
- # The components accepted are host, port, dn, attributes,
- # scope, filter, and extensions.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[host, port, dn, attributes, scope, filter, extensions]</code>.
- #
- # Example:
- #
- # uri = Gem::URI::LDAP.build({:host => 'ldap.example.com',
- # :dn => '/dc=example'})
- #
- # uri = Gem::URI::LDAP.build(["ldap.example.com", nil,
- # "/dc=example;dc=com", "query", nil, nil, nil])
- #
- def self.build(args)
- tmp = Util::make_components_hash(self, args)
-
- if tmp[:dn]
- tmp[:path] = tmp[:dn]
- end
-
- query = []
- [:extensions, :filter, :scope, :attributes].collect do |x|
- next if !tmp[x] && query.size == 0
- query.unshift(tmp[x])
- end
-
- tmp[:query] = query.join('?')
-
- return super(tmp)
- end
-
- #
- # == Description
- #
- # Creates a new Gem::URI::LDAP object from generic Gem::URI components as per
- # RFC 2396. No LDAP-specific syntax checking is performed.
- #
- # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
- # +opaque+, +query+, and +fragment+, in that order.
- #
- # Example:
- #
- # uri = Gem::URI::LDAP.new("ldap", nil, "ldap.example.com", nil, nil,
- # "/dc=example;dc=com", nil, "query", nil)
- #
- # See also Gem::URI::Generic.new.
- #
- def initialize(*arg)
- super(*arg)
-
- if @fragment
- raise InvalidURIError, 'bad LDAP URL'
- end
-
- parse_dn
- parse_query
- end
-
- # Private method to cleanup +dn+ from using the +path+ component attribute.
- def parse_dn
- raise InvalidURIError, 'bad LDAP URL' unless @path
- @dn = @path[1..-1]
- end
- private :parse_dn
-
- # Private method to cleanup +attributes+, +scope+, +filter+, and +extensions+
- # from using the +query+ component attribute.
- def parse_query
- @attributes = nil
- @scope = nil
- @filter = nil
- @extensions = nil
-
- if @query
- attrs, scope, filter, extensions = @query.split('?')
-
- @attributes = attrs if attrs && attrs.size > 0
- @scope = scope if scope && scope.size > 0
- @filter = filter if filter && filter.size > 0
- @extensions = extensions if extensions && extensions.size > 0
- end
- end
- private :parse_query
-
- # Private method to assemble +query+ from +attributes+, +scope+, +filter+, and +extensions+.
- def build_path_query
- @path = '/' + @dn
-
- query = []
- [@extensions, @filter, @scope, @attributes].each do |x|
- next if !x && query.size == 0
- query.unshift(x)
- end
- @query = query.join('?')
- end
- private :build_path_query
-
- # Returns dn.
- def dn
- @dn
- end
-
- # Private setter for dn +val+.
- def set_dn(val)
- @dn = val
- build_path_query
- @dn
- end
- protected :set_dn
-
- # Setter for dn +val+.
- def dn=(val)
- set_dn(val)
- val
- end
-
- # Returns attributes.
- def attributes
- @attributes
- end
-
- # Private setter for attributes +val+.
- def set_attributes(val)
- @attributes = val
- build_path_query
- @attributes
- end
- protected :set_attributes
-
- # Setter for attributes +val+.
- def attributes=(val)
- set_attributes(val)
- val
- end
-
- # Returns scope.
- def scope
- @scope
- end
-
- # Private setter for scope +val+.
- def set_scope(val)
- @scope = val
- build_path_query
- @scope
- end
- protected :set_scope
-
- # Setter for scope +val+.
- def scope=(val)
- set_scope(val)
- val
- end
-
- # Returns filter.
- def filter
- @filter
- end
-
- # Private setter for filter +val+.
- def set_filter(val)
- @filter = val
- build_path_query
- @filter
- end
- protected :set_filter
-
- # Setter for filter +val+.
- def filter=(val)
- set_filter(val)
- val
- end
-
- # Returns extensions.
- def extensions
- @extensions
- end
-
- # Private setter for extensions +val+.
- def set_extensions(val)
- @extensions = val
- build_path_query
- @extensions
- end
- protected :set_extensions
-
- # Setter for extensions +val+.
- def extensions=(val)
- set_extensions(val)
- val
- end
-
- # Checks if Gem::URI has a path.
- # For Gem::URI::LDAP this will return +false+.
- def hierarchical?
- false
- end
- end
-
- register_scheme 'LDAP', LDAP
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/ldaps.rb b/lib/rubygems/vendor/uri/lib/uri/ldaps.rb
deleted file mode 100644
index b7a5b50e27..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/ldaps.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: false
-# = uri/ldap.rb
-#
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'ldap'
-
-module Gem::URI
-
- # The default port for LDAPS URIs is 636, and the scheme is 'ldaps:' rather
- # than 'ldap:'. Other than that, LDAPS URIs are identical to LDAP URIs;
- # see Gem::URI::LDAP.
- class LDAPS < LDAP
- # A Default port of 636 for Gem::URI::LDAPS
- DEFAULT_PORT = 636
- end
-
- register_scheme 'LDAPS', LDAPS
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/mailto.rb b/lib/rubygems/vendor/uri/lib/uri/mailto.rb
deleted file mode 100644
index 7ae544d194..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/mailto.rb
+++ /dev/null
@@ -1,293 +0,0 @@
-# frozen_string_literal: false
-# = uri/mailto.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # RFC6068, the mailto URL scheme.
- #
- class MailTo < Generic
- include RFC2396_REGEXP
-
- # A Default port of nil for Gem::URI::MailTo.
- DEFAULT_PORT = nil
-
- # An Array of the available components for Gem::URI::MailTo.
- COMPONENT = [ :scheme, :to, :headers ].freeze
-
- # :stopdoc:
- # "hname" and "hvalue" are encodings of an RFC 822 header name and
- # value, respectively. As with "to", all URL reserved characters must
- # be encoded.
- #
- # "#mailbox" is as specified in RFC 822 [RFC822]. This means that it
- # consists of zero or more comma-separated mail addresses, possibly
- # including "phrase" and "comment" components. Note that all URL
- # reserved characters in "to" must be encoded: in particular,
- # parentheses, commas, and the percent sign ("%"), which commonly occur
- # in the "mailbox" syntax.
- #
- # Within mailto URLs, the characters "?", "=", "&" are reserved.
-
- # ; RFC 6068
- # hfields = "?" hfield *( "&" hfield )
- # hfield = hfname "=" hfvalue
- # hfname = *qchar
- # hfvalue = *qchar
- # qchar = unreserved / pct-encoded / some-delims
- # some-delims = "!" / "$" / "'" / "(" / ")" / "*"
- # / "+" / "," / ";" / ":" / "@"
- #
- # ; RFC3986
- # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- # pct-encoded = "%" HEXDIG HEXDIG
- HEADER_REGEXP = /\A(?<hfield>(?:%\h\h|[!$'-.0-;@-Z_a-z~])*=(?:%\h\h|[!$'-.0-;@-Z_a-z~])*)(?:&\g<hfield>)*\z/
- # practical regexp for email address
- # https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
- EMAIL_REGEXP = /\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/
- # :startdoc:
-
- #
- # == Description
- #
- # Creates a new Gem::URI::MailTo object from components, with syntax checking.
- #
- # Components can be provided as an Array or Hash. If an Array is used,
- # the components must be supplied as <code>[to, headers]</code>.
- #
- # If a Hash is used, the keys are the component names preceded by colons.
- #
- # The headers can be supplied as a pre-encoded string, such as
- # <code>"subject=subscribe&cc=address"</code>, or as an Array of Arrays
- # like <code>[['subject', 'subscribe'], ['cc', 'address']]</code>.
- #
- # Examples:
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # m1 = Gem::URI::MailTo.build(['joe@example.com', 'subject=Ruby'])
- # m1.to_s # => "mailto:joe@example.com?subject=Ruby"
- #
- # m2 = Gem::URI::MailTo.build(['john@example.com', [['Subject', 'Ruby'], ['Cc', 'jack@example.com']]])
- # m2.to_s # => "mailto:john@example.com?Subject=Ruby&Cc=jack@example.com"
- #
- # m3 = Gem::URI::MailTo.build({:to => 'listman@example.com', :headers => [['subject', 'subscribe']]})
- # m3.to_s # => "mailto:listman@example.com?subject=subscribe"
- #
- def self.build(args)
- tmp = Util.make_components_hash(self, args)
-
- case tmp[:to]
- when Array
- tmp[:opaque] = tmp[:to].join(',')
- when String
- tmp[:opaque] = tmp[:to].dup
- else
- tmp[:opaque] = ''
- end
-
- if tmp[:headers]
- query =
- case tmp[:headers]
- when Array
- tmp[:headers].collect { |x|
- if x.kind_of?(Array)
- x[0] + '=' + x[1..-1].join
- else
- x.to_s
- end
- }.join('&')
- when Hash
- tmp[:headers].collect { |h,v|
- h + '=' + v
- }.join('&')
- else
- tmp[:headers].to_s
- end
- unless query.empty?
- tmp[:opaque] << '?' << query
- end
- end
-
- super(tmp)
- end
-
- #
- # == Description
- #
- # Creates a new Gem::URI::MailTo object from generic URL components with
- # no syntax checking.
- #
- # This method is usually called from Gem::URI::parse, which checks
- # the validity of each component.
- #
- def initialize(*arg)
- super(*arg)
-
- @to = nil
- @headers = []
-
- # The RFC3986 parser does not normally populate opaque
- @opaque = "?#{@query}" if @query && !@opaque
-
- unless @opaque
- raise InvalidComponentError,
- "missing opaque part for mailto URL"
- end
- to, header = @opaque.split('?', 2)
- # allow semicolon as a addr-spec separator
- # http://support.microsoft.com/kb/820868
- unless /\A(?:[^@,;]+@[^@,;]+(?:\z|[,;]))*\z/ =~ to
- raise InvalidComponentError,
- "unrecognised opaque part for mailtoURL: #{@opaque}"
- end
-
- if arg[10] # arg_check
- self.to = to
- self.headers = header
- else
- set_to(to)
- set_headers(header)
- end
- end
-
- # The primary e-mail address of the URL, as a String.
- attr_reader :to
-
- # E-mail headers set by the URL, as an Array of Arrays.
- attr_reader :headers
-
- # Checks the to +v+ component.
- def check_to(v)
- return true unless v
- return true if v.size == 0
-
- v.split(/[,;]/).each do |addr|
- # check url safety as path-rootless
- if /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*\z/ !~ addr
- raise InvalidComponentError,
- "an address in 'to' is invalid as Gem::URI #{addr.dump}"
- end
-
- # check addr-spec
- # don't s/\+/ /g
- addr.gsub!(/%\h\h/, Gem::URI::TBLDECWWWCOMP_)
- if EMAIL_REGEXP !~ addr
- raise InvalidComponentError,
- "an address in 'to' is invalid as uri-escaped addr-spec #{addr.dump}"
- end
- end
-
- true
- end
- private :check_to
-
- # Private setter for to +v+.
- def set_to(v)
- @to = v
- end
- protected :set_to
-
- # Setter for to +v+.
- def to=(v)
- check_to(v)
- set_to(v)
- v
- end
-
- # Checks the headers +v+ component against either
- # * HEADER_REGEXP
- def check_headers(v)
- return true unless v
- return true if v.size == 0
- if HEADER_REGEXP !~ v
- raise InvalidComponentError,
- "bad component(expected opaque component): #{v}"
- end
-
- true
- end
- private :check_headers
-
- # Private setter for headers +v+.
- def set_headers(v)
- @headers = []
- if v
- v.split('&').each do |x|
- @headers << x.split(/=/, 2)
- end
- end
- end
- protected :set_headers
-
- # Setter for headers +v+.
- def headers=(v)
- check_headers(v)
- set_headers(v)
- v
- end
-
- # Constructs String from Gem::URI.
- def to_s
- @scheme + ':' +
- if @to
- @to
- else
- ''
- end +
- if @headers.size > 0
- '?' + @headers.collect{|x| x.join('=')}.join('&')
- else
- ''
- end +
- if @fragment
- '#' + @fragment
- else
- ''
- end
- end
-
- # Returns the RFC822 e-mail text equivalent of the URL, as a String.
- #
- # Example:
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("mailto:ruby-list@ruby-lang.org?Subject=subscribe&cc=myaddr")
- # uri.to_mailtext
- # # => "To: ruby-list@ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n"
- #
- def to_mailtext
- to = Gem::URI.decode_www_form_component(@to)
- head = ''
- body = ''
- @headers.each do |x|
- case x[0]
- when 'body'
- body = Gem::URI.decode_www_form_component(x[1])
- when 'to'
- to << ', ' + Gem::URI.decode_www_form_component(x[1])
- else
- head << Gem::URI.decode_www_form_component(x[0]).capitalize + ': ' +
- Gem::URI.decode_www_form_component(x[1]) + "\n"
- end
- end
-
- "To: #{to}
-#{head}
-#{body}
-"
- end
- alias to_rfc822text to_mailtext
- end
-
- register_scheme 'MAILTO', MailTo
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
deleted file mode 100644
index 735a269f2c..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
+++ /dev/null
@@ -1,539 +0,0 @@
-# frozen_string_literal: false
-#--
-# = uri/common.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License::
-# You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-module Gem::URI
- #
- # Includes Gem::URI::REGEXP::PATTERN
- #
- module RFC2396_REGEXP
- #
- # Patterns used to parse Gem::URI's
- #
- module PATTERN
- # :stopdoc:
-
- # RFC 2396 (Gem::URI Generic Syntax)
- # RFC 2732 (IPv6 Literal Addresses in URL's)
- # RFC 2373 (IPv6 Addressing Architecture)
-
- # alpha = lowalpha | upalpha
- ALPHA = "a-zA-Z"
- # alphanum = alpha | digit
- ALNUM = "#{ALPHA}\\d"
-
- # hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
- # "a" | "b" | "c" | "d" | "e" | "f"
- HEX = "a-fA-F\\d"
- # escaped = "%" hex hex
- ESCAPED = "%[#{HEX}]{2}"
- # mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
- # "(" | ")"
- # unreserved = alphanum | mark
- UNRESERVED = "\\-_.!~*'()#{ALNUM}"
- # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
- # "$" | ","
- # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
- # "$" | "," | "[" | "]" (RFC 2732)
- RESERVED = ";/?:@&=+$,\\[\\]"
-
- # domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
- DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
- # toplabel = alpha | alpha *( alphanum | "-" ) alphanum
- TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
- # hostname = *( domainlabel "." ) toplabel [ "." ]
- HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
-
- # :startdoc:
- end # PATTERN
-
- # :startdoc:
- end # REGEXP
-
- # Class that parses String's into Gem::URI's.
- #
- # It contains a Hash set of patterns and Regexp's that match and validate.
- #
- class RFC2396_Parser
- include RFC2396_REGEXP
-
- #
- # == Synopsis
- #
- # Gem::URI::Parser.new([opts])
- #
- # == Args
- #
- # The constructor accepts a hash as options for parser.
- # Keys of options are pattern names of Gem::URI components
- # and values of options are pattern strings.
- # The constructor generates set of regexps for parsing URIs.
- #
- # You can use the following keys:
- #
- # * :ESCAPED (Gem::URI::PATTERN::ESCAPED in default)
- # * :UNRESERVED (Gem::URI::PATTERN::UNRESERVED in default)
- # * :DOMLABEL (Gem::URI::PATTERN::DOMLABEL in default)
- # * :TOPLABEL (Gem::URI::PATTERN::TOPLABEL in default)
- # * :HOSTNAME (Gem::URI::PATTERN::HOSTNAME in default)
- #
- # == Examples
- #
- # p = Gem::URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
- # u = p.parse("http://example.jp/%uABCD") #=> #<Gem::URI::HTTP http://example.jp/%uABCD>
- # Gem::URI.parse(u.to_s) #=> raises Gem::URI::InvalidURIError
- #
- # s = "http://example.com/ABCD"
- # u1 = p.parse(s) #=> #<Gem::URI::HTTP http://example.com/ABCD>
- # u2 = Gem::URI.parse(s) #=> #<Gem::URI::HTTP http://example.com/ABCD>
- # u1 == u2 #=> true
- # u1.eql?(u2) #=> false
- #
- def initialize(opts = {})
- @pattern = initialize_pattern(opts)
- @pattern.each_value(&:freeze)
- @pattern.freeze
-
- @regexp = initialize_regexp(@pattern)
- @regexp.each_value(&:freeze)
- @regexp.freeze
- end
-
- # The Hash of patterns.
- #
- # See also Gem::URI::Parser.initialize_pattern.
- attr_reader :pattern
-
- # The Hash of Regexp.
- #
- # See also Gem::URI::Parser.initialize_regexp.
- attr_reader :regexp
-
- # Returns a split Gem::URI against +regexp[:ABS_URI]+.
- def split(uri)
- case uri
- when ''
- # null uri
-
- when @regexp[:ABS_URI]
- scheme, opaque, userinfo, host, port,
- registry, path, query, fragment = $~[1..-1]
-
- # Gem::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
-
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
- # hier_part = ( net_path | abs_path ) [ "?" query ]
- # opaque_part = uric_no_slash *uric
-
- # abs_path = "/" path_segments
- # net_path = "//" authority [ abs_path ]
-
- # authority = server | reg_name
- # server = [ [ userinfo "@" ] hostport ]
-
- if !scheme
- raise InvalidURIError,
- "bad Gem::URI(absolute but no scheme): #{uri}"
- end
- if !opaque && (!path && (!host && !registry))
- raise InvalidURIError,
- "bad Gem::URI(absolute but no path): #{uri}"
- end
-
- when @regexp[:REL_URI]
- scheme = nil
- opaque = nil
-
- userinfo, host, port, registry,
- rel_segment, abs_path, query, fragment = $~[1..-1]
- if rel_segment && abs_path
- path = rel_segment + abs_path
- elsif rel_segment
- path = rel_segment
- elsif abs_path
- path = abs_path
- end
-
- # Gem::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
-
- # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
-
- # net_path = "//" authority [ abs_path ]
- # abs_path = "/" path_segments
- # rel_path = rel_segment [ abs_path ]
-
- # authority = server | reg_name
- # server = [ [ userinfo "@" ] hostport ]
-
- else
- raise InvalidURIError, "bad Gem::URI(is not Gem::URI?): #{uri}"
- end
-
- path = '' if !path && !opaque # (see RFC2396 Section 5.2)
- ret = [
- scheme,
- userinfo, host, port, # X
- registry, # X
- path, # Y
- opaque, # Y
- query,
- fragment
- ]
- return ret
- end
-
- #
- # == Args
- #
- # +uri+::
- # String
- #
- # == Description
- #
- # Parses +uri+ and constructs either matching Gem::URI scheme object
- # (File, FTP, HTTP, HTTPS, LDAP, LDAPS, or MailTo) or Gem::URI::Generic.
- #
- # == Usage
- #
- # p = Gem::URI::Parser.new
- # p.parse("ldap://ldap.example.com/dc=example?user=john")
- # #=> #<Gem::URI::LDAP ldap://ldap.example.com/dc=example?user=john>
- #
- def parse(uri)
- Gem::URI.for(*self.split(uri), self)
- end
-
- #
- # == Args
- #
- # +uris+::
- # an Array of Strings
- #
- # == Description
- #
- # Attempts to parse and merge a set of URIs.
- #
- def join(*uris)
- uris[0] = convert_to_uri(uris[0])
- uris.inject :merge
- end
-
- #
- # :call-seq:
- # extract( str )
- # extract( str, schemes )
- # extract( str, schemes ) {|item| block }
- #
- # == Args
- #
- # +str+::
- # String to search
- # +schemes+::
- # Patterns to apply to +str+
- #
- # == Description
- #
- # Attempts to parse and merge a set of URIs.
- # If no +block+ given, then returns the result,
- # else it calls +block+ for each element in result.
- #
- # See also Gem::URI::Parser.make_regexp.
- #
- def extract(str, schemes = nil)
- if block_given?
- str.scan(make_regexp(schemes)) { yield $& }
- nil
- else
- result = []
- str.scan(make_regexp(schemes)) { result.push $& }
- result
- end
- end
-
- # Returns Regexp that is default +self.regexp[:ABS_URI_REF]+,
- # unless +schemes+ is provided. Then it is a Regexp.union with +self.pattern[:X_ABS_URI]+.
- def make_regexp(schemes = nil)
- unless schemes
- @regexp[:ABS_URI_REF]
- else
- /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x
- end
- end
-
- #
- # :call-seq:
- # escape( str )
- # escape( str, unsafe )
- #
- # == Args
- #
- # +str+::
- # String to make safe
- # +unsafe+::
- # Regexp to apply. Defaults to +self.regexp[:UNSAFE]+
- #
- # == Description
- #
- # Constructs a safe String from +str+, removing unsafe characters,
- # replacing them with codes.
- #
- def escape(str, unsafe = @regexp[:UNSAFE])
- unless unsafe.kind_of?(Regexp)
- # perhaps unsafe is String object
- unsafe = Regexp.new("[#{Regexp.quote(unsafe)}]", false)
- end
- str.gsub(unsafe) do
- us = $&
- tmp = ''
- us.each_byte do |uc|
- tmp << sprintf('%%%02X', uc)
- end
- tmp
- end.force_encoding(Encoding::US_ASCII)
- end
-
- #
- # :call-seq:
- # unescape( str )
- # unescape( str, escaped )
- #
- # == Args
- #
- # +str+::
- # String to remove escapes from
- # +escaped+::
- # Regexp to apply. Defaults to +self.regexp[:ESCAPED]+
- #
- # == Description
- #
- # Removes escapes from +str+.
- #
- def unescape(str, escaped = @regexp[:ESCAPED])
- enc = str.encoding
- enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
- str.gsub(escaped) { [$&[1, 2]].pack('H2').force_encoding(enc) }
- end
-
- @@to_s = Kernel.instance_method(:to_s)
- if @@to_s.respond_to?(:bind_call)
- def inspect
- @@to_s.bind_call(self)
- end
- else
- def inspect
- @@to_s.bind(self).call
- end
- end
-
- private
-
- # Constructs the default Hash of patterns.
- def initialize_pattern(opts = {})
- ret = {}
- ret[:ESCAPED] = escaped = (opts.delete(:ESCAPED) || PATTERN::ESCAPED)
- ret[:UNRESERVED] = unreserved = opts.delete(:UNRESERVED) || PATTERN::UNRESERVED
- ret[:RESERVED] = reserved = opts.delete(:RESERVED) || PATTERN::RESERVED
- ret[:DOMLABEL] = opts.delete(:DOMLABEL) || PATTERN::DOMLABEL
- ret[:TOPLABEL] = opts.delete(:TOPLABEL) || PATTERN::TOPLABEL
- ret[:HOSTNAME] = hostname = opts.delete(:HOSTNAME)
-
- # RFC 2396 (Gem::URI Generic Syntax)
- # RFC 2732 (IPv6 Literal Addresses in URL's)
- # RFC 2373 (IPv6 Addressing Architecture)
-
- # uric = reserved | unreserved | escaped
- ret[:URIC] = uric = "(?:[#{unreserved}#{reserved}]|#{escaped})"
- # uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
- # "&" | "=" | "+" | "$" | ","
- ret[:URIC_NO_SLASH] = uric_no_slash = "(?:[#{unreserved};?:@&=+$,]|#{escaped})"
- # query = *uric
- ret[:QUERY] = query = "#{uric}*"
- # fragment = *uric
- ret[:FRAGMENT] = fragment = "#{uric}*"
-
- # hostname = *( domainlabel "." ) toplabel [ "." ]
- # reg-name = *( unreserved / pct-encoded / sub-delims ) # RFC3986
- unless hostname
- ret[:HOSTNAME] = hostname = "(?:[a-zA-Z0-9\\-.]|%\\h\\h)+"
- end
-
- # RFC 2373, APPENDIX B:
- # IPv6address = hexpart [ ":" IPv4address ]
- # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
- # hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
- # hexseq = hex4 *( ":" hex4)
- # hex4 = 1*4HEXDIG
- #
- # XXX: This definition has a flaw. "::" + IPv4address must be
- # allowed too. Here is a replacement.
- #
- # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
- ret[:IPV4ADDR] = ipv4addr = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"
- # hex4 = 1*4HEXDIG
- hex4 = "[#{PATTERN::HEX}]{1,4}"
- # lastpart = hex4 | IPv4address
- lastpart = "(?:#{hex4}|#{ipv4addr})"
- # hexseq1 = *( hex4 ":" ) hex4
- hexseq1 = "(?:#{hex4}:)*#{hex4}"
- # hexseq2 = *( hex4 ":" ) lastpart
- hexseq2 = "(?:#{hex4}:)*#{lastpart}"
- # IPv6address = hexseq2 | [ hexseq1 ] "::" [ hexseq2 ]
- ret[:IPV6ADDR] = ipv6addr = "(?:#{hexseq2}|(?:#{hexseq1})?::(?:#{hexseq2})?)"
-
- # IPv6prefix = ( hexseq1 | [ hexseq1 ] "::" [ hexseq1 ] ) "/" 1*2DIGIT
- # unused
-
- # ipv6reference = "[" IPv6address "]" (RFC 2732)
- ret[:IPV6REF] = ipv6ref = "\\[#{ipv6addr}\\]"
-
- # host = hostname | IPv4address
- # host = hostname | IPv4address | IPv6reference (RFC 2732)
- ret[:HOST] = host = "(?:#{hostname}|#{ipv4addr}|#{ipv6ref})"
- # port = *digit
- ret[:PORT] = port = '\d*'
- # hostport = host [ ":" port ]
- ret[:HOSTPORT] = hostport = "#{host}(?::#{port})?"
-
- # userinfo = *( unreserved | escaped |
- # ";" | ":" | "&" | "=" | "+" | "$" | "," )
- ret[:USERINFO] = userinfo = "(?:[#{unreserved};:&=+$,]|#{escaped})*"
-
- # pchar = unreserved | escaped |
- # ":" | "@" | "&" | "=" | "+" | "$" | ","
- pchar = "(?:[#{unreserved}:@&=+$,]|#{escaped})"
- # param = *pchar
- param = "#{pchar}*"
- # segment = *pchar *( ";" param )
- segment = "#{pchar}*(?:;#{param})*"
- # path_segments = segment *( "/" segment )
- ret[:PATH_SEGMENTS] = path_segments = "#{segment}(?:/#{segment})*"
-
- # server = [ [ userinfo "@" ] hostport ]
- server = "(?:#{userinfo}@)?#{hostport}"
- # reg_name = 1*( unreserved | escaped | "$" | "," |
- # ";" | ":" | "@" | "&" | "=" | "+" )
- ret[:REG_NAME] = reg_name = "(?:[#{unreserved}$,;:@&=+]|#{escaped})+"
- # authority = server | reg_name
- authority = "(?:#{server}|#{reg_name})"
-
- # rel_segment = 1*( unreserved | escaped |
- # ";" | "@" | "&" | "=" | "+" | "$" | "," )
- ret[:REL_SEGMENT] = rel_segment = "(?:[#{unreserved};@&=+$,]|#{escaped})+"
-
- # scheme = alpha *( alpha | digit | "+" | "-" | "." )
- ret[:SCHEME] = scheme = "[#{PATTERN::ALPHA}][\\-+.#{PATTERN::ALPHA}\\d]*"
-
- # abs_path = "/" path_segments
- ret[:ABS_PATH] = abs_path = "/#{path_segments}"
- # rel_path = rel_segment [ abs_path ]
- ret[:REL_PATH] = rel_path = "#{rel_segment}(?:#{abs_path})?"
- # net_path = "//" authority [ abs_path ]
- ret[:NET_PATH] = net_path = "//#{authority}(?:#{abs_path})?"
-
- # hier_part = ( net_path | abs_path ) [ "?" query ]
- ret[:HIER_PART] = hier_part = "(?:#{net_path}|#{abs_path})(?:\\?(?:#{query}))?"
- # opaque_part = uric_no_slash *uric
- ret[:OPAQUE_PART] = opaque_part = "#{uric_no_slash}#{uric}*"
-
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
- ret[:ABS_URI] = abs_uri = "#{scheme}:(?:#{hier_part}|#{opaque_part})"
- # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- ret[:REL_URI] = rel_uri = "(?:#{net_path}|#{abs_path}|#{rel_path})(?:\\?#{query})?"
-
- # Gem::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- ret[:URI_REF] = "(?:#{abs_uri}|#{rel_uri})?(?:##{fragment})?"
-
- ret[:X_ABS_URI] = "
- (#{scheme}): (?# 1: scheme)
- (?:
- (#{opaque_part}) (?# 2: opaque)
- |
- (?:(?:
- //(?:
- (?:(?:(#{userinfo})@)? (?# 3: userinfo)
- (?:(#{host})(?::(\\d*))?))? (?# 4: host, 5: port)
- |
- (#{reg_name}) (?# 6: registry)
- )
- |
- (?!//)) (?# XXX: '//' is the mark for hostport)
- (#{abs_path})? (?# 7: path)
- )(?:\\?(#{query}))? (?# 8: query)
- )
- (?:\\#(#{fragment}))? (?# 9: fragment)
- "
-
- ret[:X_REL_URI] = "
- (?:
- (?:
- //
- (?:
- (?:(#{userinfo})@)? (?# 1: userinfo)
- (#{host})?(?::(\\d*))? (?# 2: host, 3: port)
- |
- (#{reg_name}) (?# 4: registry)
- )
- )
- |
- (#{rel_segment}) (?# 5: rel_segment)
- )?
- (#{abs_path})? (?# 6: abs_path)
- (?:\\?(#{query}))? (?# 7: query)
- (?:\\#(#{fragment}))? (?# 8: fragment)
- "
-
- ret
- end
-
- # Constructs the default Hash of Regexp's.
- def initialize_regexp(pattern)
- ret = {}
-
- # for Gem::URI::split
- ret[:ABS_URI] = Regexp.new('\A\s*+' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
- ret[:REL_URI] = Regexp.new('\A\s*+' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
-
- # for Gem::URI::extract
- ret[:URI_REF] = Regexp.new(pattern[:URI_REF])
- ret[:ABS_URI_REF] = Regexp.new(pattern[:X_ABS_URI], Regexp::EXTENDED)
- ret[:REL_URI_REF] = Regexp.new(pattern[:X_REL_URI], Regexp::EXTENDED)
-
- # for Gem::URI::escape/unescape
- ret[:ESCAPED] = Regexp.new(pattern[:ESCAPED])
- ret[:UNSAFE] = Regexp.new("[^#{pattern[:UNRESERVED]}#{pattern[:RESERVED]}]")
-
- # for Generic#initialize
- ret[:SCHEME] = Regexp.new("\\A#{pattern[:SCHEME]}\\z")
- ret[:USERINFO] = Regexp.new("\\A#{pattern[:USERINFO]}\\z")
- ret[:HOST] = Regexp.new("\\A#{pattern[:HOST]}\\z")
- ret[:PORT] = Regexp.new("\\A#{pattern[:PORT]}\\z")
- ret[:OPAQUE] = Regexp.new("\\A#{pattern[:OPAQUE_PART]}\\z")
- ret[:REGISTRY] = Regexp.new("\\A#{pattern[:REG_NAME]}\\z")
- ret[:ABS_PATH] = Regexp.new("\\A#{pattern[:ABS_PATH]}\\z")
- ret[:REL_PATH] = Regexp.new("\\A#{pattern[:REL_PATH]}\\z")
- ret[:QUERY] = Regexp.new("\\A#{pattern[:QUERY]}\\z")
- ret[:FRAGMENT] = Regexp.new("\\A#{pattern[:FRAGMENT]}\\z")
-
- ret
- end
-
- def convert_to_uri(uri)
- if uri.is_a?(Gem::URI::Generic)
- uri
- elsif uri = String.try_convert(uri)
- parse(uri)
- else
- raise ArgumentError,
- "bad argument (expected Gem::URI object or Gem::URI string)"
- end
- end
-
- end # class Parser
-end # module Gem::URI
diff --git a/lib/rubygems/vendor/uri/lib/uri/rfc3986_parser.rb b/lib/rubygems/vendor/uri/lib/uri/rfc3986_parser.rb
deleted file mode 100644
index 728bb55674..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/rfc3986_parser.rb
+++ /dev/null
@@ -1,183 +0,0 @@
-# frozen_string_literal: true
-module Gem::URI
- class RFC3986_Parser # :nodoc:
- # Gem::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}
- (?<Gem::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
- attr_reader :regexp
-
- def initialize
- @regexp = default_regexp.each_value(&:freeze).freeze
- end
-
- def split(uri) #:nodoc:
- begin
- uri = uri.to_str
- rescue NoMethodError
- raise InvalidURIError, "bad Gem::URI(is not Gem::URI?): #{uri.inspect}"
- end
- uri.ascii_only? or
- raise InvalidURIError, "Gem::URI must be ascii only #{uri.dump}"
- if m = RFC3986_URI.match(uri)
- query = m["query"]
- scheme = m["scheme"]
- opaque = m["path-rootless"]
- if opaque
- opaque << "?#{query}" if query
- [ scheme,
- nil, # userinfo
- nil, # host
- nil, # port
- nil, # registry
- nil, # path
- opaque,
- nil, # query
- m["fragment"]
- ]
- else # normal
- [ scheme,
- m["userinfo"],
- m["host"],
- m["port"],
- nil, # registry
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-empty"]),
- nil, # opaque
- query,
- m["fragment"]
- ]
- end
- elsif m = RFC3986_relative_ref.match(uri)
- [ nil, # scheme
- m["userinfo"],
- m["host"],
- m["port"],
- nil, # registry,
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-noscheme"] ||
- m["path-empty"]),
- nil, # opaque
- m["query"],
- m["fragment"]
- ]
- else
- raise InvalidURIError, "bad Gem::URI(is not Gem::URI?): #{uri.inspect}"
- end
- end
-
- def parse(uri) # :nodoc:
- Gem::URI.for(*self.split(uri), self)
- end
-
-
- def join(*uris) # :nodoc:
- uris[0] = convert_to_uri(uris[0])
- uris.inject :merge
- end
-
- @@to_s = Kernel.instance_method(:to_s)
- if @@to_s.respond_to?(:bind_call)
- def inspect
- @@to_s.bind_call(self)
- end
- else
- def inspect
- @@to_s.bind(self).call
- end
- end
-
- private
-
- 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],
- PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\z/,
- }
- end
-
- def convert_to_uri(uri)
- if uri.is_a?(Gem::URI::Generic)
- uri
- elsif uri = String.try_convert(uri)
- parse(uri)
- else
- raise ArgumentError,
- "bad argument (expected Gem::URI object or Gem::URI string)"
- end
- end
-
- end # class Parser
-end # module Gem::URI
diff --git a/lib/rubygems/vendor/uri/lib/uri/version.rb b/lib/rubygems/vendor/uri/lib/uri/version.rb
deleted file mode 100644
index 080744095c..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/version.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-module Gem::URI
- # :stopdoc:
- VERSION_CODE = '001301'.freeze
- VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
- # :startdoc:
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/ws.rb b/lib/rubygems/vendor/uri/lib/uri/ws.rb
deleted file mode 100644
index 0dd2a7a1bb..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/ws.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# frozen_string_literal: false
-# = uri/ws.rb
-#
-# Author:: Matt Muller <mamuller@amazon.com>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # The syntax of WS URIs is defined in RFC6455 section 3.
- #
- # Note that the Ruby Gem::URI library allows WS URLs containing usernames and
- # passwords. This is not legal as per the RFC, but used to be
- # supported in Internet Explorer 5 and 6, before the MS04-004 security
- # update. See <URL:http://support.microsoft.com/kb/834489>.
- #
- class WS < Generic
- # A Default port of 80 for Gem::URI::WS.
- DEFAULT_PORT = 80
-
- # An Array of the available components for Gem::URI::WS.
- COMPONENT = %i[
- scheme
- userinfo host port
- path
- query
- ].freeze
-
- #
- # == Description
- #
- # Creates a new Gem::URI::WS object from components, with syntax checking.
- #
- # The components accepted are userinfo, host, port, path, and query.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[userinfo, host, port, path, query]</code>.
- #
- # Example:
- #
- # uri = Gem::URI::WS.build(host: 'www.example.com', path: '/foo/bar')
- #
- # uri = Gem::URI::WS.build([nil, "www.example.com", nil, "/path", "query"])
- #
- # Currently, if passed userinfo components this method generates
- # invalid WS URIs as per RFC 1738.
- #
- def self.build(args)
- tmp = Util.make_components_hash(self, args)
- super(tmp)
- end
-
- #
- # == Description
- #
- # Returns the full path for a WS Gem::URI, as required by Net::HTTP::Get.
- #
- # If the Gem::URI contains a query, the full path is Gem::URI#path + '?' + Gem::URI#query.
- # Otherwise, the path is simply Gem::URI#path.
- #
- # Example:
- #
- # uri = Gem::URI::WS.build(path: '/foo/bar', query: 'test=true')
- # uri.request_uri # => "/foo/bar?test=true"
- #
- def request_uri
- return unless @path
-
- url = @query ? "#@path?#@query" : @path.dup
- url.start_with?(?/.freeze) ? url : ?/ + url
- end
- end
-
- register_scheme 'WS', WS
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/wss.rb b/lib/rubygems/vendor/uri/lib/uri/wss.rb
deleted file mode 100644
index 0b91d334bb..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/wss.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: false
-# = uri/wss.rb
-#
-# Author:: Matt Muller <mamuller@amazon.com>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'ws'
-
-module Gem::URI
-
- # The default port for WSS URIs is 443, and the scheme is 'wss:' rather
- # than 'ws:'. Other than that, WSS URIs are identical to WS URIs;
- # see Gem::URI::WS.
- class WSS < WS
- # A Default port of 443 for Gem::URI::WSS
- DEFAULT_PORT = 443
- end
-
- register_scheme 'WSS', WSS
-end
diff --git a/lib/rubygems/vendored_molinillo.rb b/lib/rubygems/vendored_molinillo.rb
deleted file mode 100644
index 45906c0e5c..0000000000
--- a/lib/rubygems/vendored_molinillo.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "vendor/molinillo/lib/molinillo"
diff --git a/lib/rubygems/vendored_net_http.rb b/lib/rubygems/vendored_net_http.rb
deleted file mode 100644
index a84c52a947..0000000000
--- a/lib/rubygems/vendored_net_http.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: true
-
-# Ruby 3.3 and RubyGems 3.5 is already load Gem::Timeout from lib/rubygems/net/http.rb
-# We should avoid to load it again
-require_relative "vendor/net-http/lib/net/http" unless defined?(Gem::Net::HTTP)
diff --git a/lib/rubygems/vendored_optparse.rb b/lib/rubygems/vendored_optparse.rb
deleted file mode 100644
index a5611d32f0..0000000000
--- a/lib/rubygems/vendored_optparse.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "vendor/optparse/lib/optparse"
diff --git a/lib/rubygems/vendored_securerandom.rb b/lib/rubygems/vendored_securerandom.rb
deleted file mode 100644
index 0ce26905c4..0000000000
--- a/lib/rubygems/vendored_securerandom.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Random; end
-require_relative "vendor/securerandom/lib/securerandom"
diff --git a/lib/rubygems/vendored_timeout.rb b/lib/rubygems/vendored_timeout.rb
deleted file mode 100644
index 45541928e6..0000000000
--- a/lib/rubygems/vendored_timeout.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: true
-
-# Ruby 3.3 and RubyGems 3.5 is already load Gem::Timeout from lib/rubygems/timeout.rb
-# We should avoid to load it again
-require_relative "vendor/timeout/lib/timeout" unless defined?(Gem::Timeout)
diff --git a/lib/rubygems/vendored_tsort.rb b/lib/rubygems/vendored_tsort.rb
deleted file mode 100644
index c3d815650d..0000000000
--- a/lib/rubygems/vendored_tsort.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "vendor/tsort/lib/tsort"
diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb
index e174d8ad95..f67889ef1a 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
@@ -155,17 +155,17 @@ require_relative "deprecate"
class Gem::Version
include Comparable
- VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?' # :nodoc:
- ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/ # :nodoc:
+ VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?'.freeze # :nodoc:
+ ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/.freeze # :nodoc:
##
# 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:
@@ -280,7 +272,7 @@ class Gem::Version
# string for backwards (RubyGems 1.3.5 and earlier) compatibility.
def marshal_dump
- [@version]
+ [version]
end
##
@@ -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..a487a0bc24 100644
--- a/lib/rubygems/version_option.rb
+++ b/lib/rubygems/version_option.rb
@@ -1,5 +1,4 @@
# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
@@ -12,6 +11,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 +25,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 +56,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 f89004f32a..0000000000
--- a/lib/rubygems/yaml_serializer.rb
+++ /dev/null
@@ -1,98 +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
-
- HASH_REGEX = /
- ^
- ([ ]*) # indentations
- ([^#]+) # key excludes comment char '#'
- (?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value)
- [ ]?
- (['"]?) # optional opening quote
- (.*) # value
- \3 # matching closing quote
- $
- /xo
-
- def load(str)
- res = {}
- stack = [res]
- last_hash = nil
- last_empty_key = nil
- str.split(/\r?\n/) do |line|
- if match = HASH_REGEX.match(line)
- indent, key, quote, val = match.captures
- val = strip_comment(val)
-
- 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
- val = strip_comment(val)
-
- 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
-
- def strip_comment(val)
- if val.include?("#") && !val.start_with?("#")
- val.split("#", 2).first.strip
- else
- val
- end
- end
-
- class << self
- private :dump_hash
- 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 81757f3100..07ae048634 100644
--- a/lib/securerandom.rb
+++ b/lib/securerandom.rb
@@ -39,28 +39,28 @@ require 'random/formatter'
# +NotImplementedError+ is raised.
module SecureRandom
-
- # The version
- VERSION = "0.3.1"
-
class << self
- # Returns a random binary string containing +size+ bytes.
- #
- # See Random.bytes
def bytes(n)
return gen_random(n)
end
private
- # :stopdoc:
-
- # Implementation using OpenSSL
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
- # Implementation using system random device
def gen_random_urandom(n)
ret = Random.urandom(n)
unless ret
@@ -86,9 +86,6 @@ module SecureRandom
end
end
- # :startdoc:
-
- # Generate random data bytes for Random::Formatter
public :gen_random
end
end
diff --git a/lib/set.rb b/lib/set.rb
index a0954a31d1..df1e68d081 100644
--- a/lib/set.rb
+++ b/lib/set.rb
@@ -3,7 +3,7 @@
#
# set.rb - defines the Set class
#
-# Copyright (c) 2002-2023 Akinori MUSHA <knu@iDaemons.org>
+# Copyright (c) 2002-2020 Akinori MUSHA <knu@iDaemons.org>
#
# Documentation by Akinori MUSHA and Gavin Sinclair.
#
@@ -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.1.0"
-
include Enumerable
# Creates a new set containing the given objects.
@@ -286,10 +288,18 @@ class Set
@hash = orig.instance_variable_get(:@hash).dup
end
- # Clone internal hash.
- def initialize_clone(orig, **options)
- super
- @hash = orig.instance_variable_get(:@hash).clone(**options)
+ if Kernel.instance_method(:initialize_clone).arity != 1
+ # Clone internal hash.
+ def initialize_clone(orig, **options)
+ super
+ @hash = orig.instance_variable_get(:@hash).clone(**options)
+ end
+ else
+ # Clone internal hash.
+ def initialize_clone(orig)
+ super
+ @hash = orig.instance_variable_get(:@hash).clone
+ end
end
def freeze # :nodoc:
@@ -381,7 +391,7 @@ class Set
# Equivalent to Set#flatten, but replaces the receiver with the
# result in place. Returns nil if no modifications were made.
def flatten!
- replace(flatten()) if any?(Set)
+ replace(flatten()) if any? { |e| e.is_a?(Set) }
end
# Returns true if the set contains the given object.
@@ -401,7 +411,7 @@ class Set
when set.instance_of?(self.class) && @hash.respond_to?(:>=)
@hash >= set.instance_variable_get(:@hash)
when set.is_a?(Set)
- size >= set.size && set.all?(self)
+ size >= set.size && set.all? { |o| include?(o) }
else
raise ArgumentError, "value must be a set"
end
@@ -414,7 +424,7 @@ class Set
when set.instance_of?(self.class) && @hash.respond_to?(:>)
@hash > set.instance_variable_get(:@hash)
when set.is_a?(Set)
- size > set.size && set.all?(self)
+ size > set.size && set.all? { |o| include?(o) }
else
raise ArgumentError, "value must be a set"
end
@@ -427,7 +437,7 @@ class Set
when set.instance_of?(self.class) && @hash.respond_to?(:<=)
@hash <= set.instance_variable_get(:@hash)
when set.is_a?(Set)
- size <= set.size && all?(set)
+ size <= set.size && all? { |o| set.include?(o) }
else
raise ArgumentError, "value must be a set"
end
@@ -440,7 +450,7 @@ class Set
when set.instance_of?(self.class) && @hash.respond_to?(:<)
@hash < set.instance_variable_get(:@hash)
when set.is_a?(Set)
- size < set.size && all?(set)
+ size < set.size && all? { |o| set.include?(o) }
else
raise ArgumentError, "value must be a set"
end
@@ -471,12 +481,12 @@ class Set
case set
when Set
if size < set.size
- any?(set)
+ any? { |o| set.include?(o) }
else
- set.any?(self)
+ set.any? { |o| include?(o) }
end
when Enumerable
- set.any?(self)
+ set.any? { |o| include?(o) }
else
raise ArgumentError, "value must be enumerable"
end
@@ -497,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
@@ -572,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
@@ -581,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
@@ -590,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 2ebef6985d..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(">= 3.0.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/api.rb b/lib/syntax_suggest/api.rb
index 65660ec5e5..5b725e13d7 100644
--- a/lib/syntax_suggest/api.rb
+++ b/lib/syntax_suggest/api.rb
@@ -5,27 +5,8 @@ require_relative "version"
require "tmpdir"
require "stringio"
require "pathname"
-require "timeout"
-
-# We need Ripper loaded for `Prism.lex_compat` even if we're using Prism
-# for lexing and parsing
require "ripper"
-
-# Prism is the new parser, replacing Ripper
-#
-# We need to "dual boot" both for now because syntax_suggest
-# supports older rubies that do not ship with syntax suggest.
-#
-# We also need the ability to control loading of this library
-# so we can test that both modes work correctly in CI.
-if (value = ENV["SYNTAX_SUGGEST_DISABLE_PRISM"])
- warn "Skipping loading prism due to SYNTAX_SUGGEST_DISABLE_PRISM=#{value}"
-else
- begin
- require "prism"
- rescue LoadError
- end
-end
+require "timeout"
module SyntaxSuggest
# Used to indicate a default value that cannot
@@ -35,14 +16,6 @@ module SyntaxSuggest
class Error < StandardError; end
TIMEOUT_DEFAULT = ENV.fetch("SYNTAX_SUGGEST_TIMEOUT", 1).to_i
- # SyntaxSuggest.use_prism_parser? [Private]
- #
- # Tells us if the prism parser is available for use
- # or if we should fallback to `Ripper`
- def self.use_prism_parser?
- defined?(Prism)
- end
-
# SyntaxSuggest.handle_error [Public]
#
# Takes a `SyntaxError` exception, uses the
@@ -105,7 +78,7 @@ module SyntaxSuggest
code_lines: search.code_lines
).call
rescue Timeout::Error => e
- io.puts "Search timed out SYNTAX_SUGGEST_TIMEOUT=#{timeout}, run with SYNTAX_SUGGEST_DEBUG=1 for more info"
+ io.puts "Search timed out SYNTAX_SUGGEST_TIMEOUT=#{timeout}, run with DEBUG=1 for more info"
io.puts e.backtrace.first(3).join($/)
end
@@ -118,9 +91,7 @@ module SyntaxSuggest
dir = Pathname(dir)
dir.join(time).tap { |path|
path.mkpath
- alias_dir = dir.join("last")
- FileUtils.rm_rf(alias_dir) if alias_dir.exist?
- FileUtils.ln_sf(time, alias_dir)
+ FileUtils.ln_sf(time, dir.join("last"))
}
end
@@ -156,20 +127,11 @@ module SyntaxSuggest
# SyntaxSuggest.invalid? [Private]
#
# Opposite of `SyntaxSuggest.valid?`
- if defined?(Prism)
- def self.invalid?(source)
- source = source.join if source.is_a?(Array)
- source = source.to_s
+ def self.invalid?(source)
+ source = source.join if source.is_a?(Array)
+ source = source.to_s
- Prism.parse(source).failure?
- end
- else
- def self.invalid?(source)
- source = source.join if source.is_a?(Array)
- source = source.to_s
-
- Ripper.new(source).tap(&:parse).error?
- end
+ Ripper.new(source).tap(&:parse).error?
end
# SyntaxSuggest.valid? [Private]
@@ -227,6 +189,7 @@ require_relative "lex_all"
require_relative "code_line"
require_relative "code_block"
require_relative "block_expand"
+require_relative "ripper_errors"
require_relative "priority_queue"
require_relative "unvisited_lines"
require_relative "around_block_scan"
diff --git a/lib/syntax_suggest/around_block_scan.rb b/lib/syntax_suggest/around_block_scan.rb
index dd9af729c5..2a57d1b19e 100644
--- a/lib/syntax_suggest/around_block_scan.rb
+++ b/lib/syntax_suggest/around_block_scan.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative "scan_history"
-
module SyntaxSuggest
# This class is useful for exploring contents before and after
# a block
@@ -26,207 +24,201 @@ module SyntaxSuggest
# puts scan.before_index # => 0
# puts scan.after_index # => 3
#
+ # Contents can also be filtered using AroundBlockScan#skip
+ #
+ # To grab the next surrounding indentation use AroundBlockScan#scan_adjacent_indent
class AroundBlockScan
def initialize(code_lines:, block:)
@code_lines = code_lines
+ @orig_before_index = block.lines.first.index
+ @orig_after_index = block.lines.last.index
@orig_indent = block.current_indent
-
+ @skip_array = []
+ @after_array = []
+ @before_array = []
@stop_after_kw = false
- @force_add_empty = false
- @force_add_hidden = false
- @target_indent = nil
-
- @scanner = ScanHistory.new(code_lines: code_lines, block: block)
- end
-
- # When using this flag, `scan_while` will
- # bypass the block it's given and always add a
- # line that responds truthy to `CodeLine#hidden?`
- #
- # Lines are hidden when they've been evaluated by
- # the parser as part of a block and found to contain
- # valid code.
- def force_add_hidden
- @force_add_hidden = true
- self
+
+ @skip_hidden = false
+ @skip_empty = false
end
- # When using this flag, `scan_while` will
- # bypass the block it's given and always add a
- # line that responds truthy to `CodeLine#empty?`
- #
- # Empty lines contain no code, only whitespace such
- # as leading spaces a newline.
- def force_add_empty
- @force_add_empty = true
+ def skip(name)
+ case name
+ when :hidden?
+ @skip_hidden = true
+ when :empty?
+ @skip_empty = true
+ else
+ raise "Unsupported skip #{name}"
+ end
self
end
- # Tells `scan_while` to look for mismatched keyword/end-s
- #
- # When scanning up, if we see more keywords then end-s it will
- # stop. This might happen when scanning outside of a method body.
- # the first scan line up would be a keyword and this setting would
- # trigger a stop.
- #
- # When scanning down, stop if there are more end-s than keywords.
def stop_after_kw
@stop_after_kw = true
self
end
- # Main work method
- #
- # The scan_while method takes a block that yields lines above and
- # below the block. If the yield returns true, the @before_index
- # or @after_index are modified to include the matched line.
- #
- # In addition to yielding individual lines, the internals of this
- # object give a mini DSL to handle common situations such as
- # stopping if we've found a keyword/end mis-match in one direction
- # or the other.
def scan_while
- stop_next_up = false
- stop_next_down = false
+ stop_next = false
- @scanner.scan(
- up: ->(line, kw_count, end_count) {
- next false if stop_next_up
- next true if @force_add_hidden && line.hidden?
- next true if @force_add_empty && line.empty?
+ kw_count = 0
+ end_count = 0
+ index = before_lines.reverse_each.take_while do |line|
+ next false if stop_next
+ next true if @skip_hidden && line.hidden?
+ next true if @skip_empty && line.empty?
- if @stop_after_kw && kw_count > end_count
- stop_next_up = true
- end
+ kw_count += 1 if line.is_kw?
+ end_count += 1 if line.is_end?
+ if @stop_after_kw && kw_count > end_count
+ stop_next = true
+ end
- yield line
- },
- down: ->(line, kw_count, end_count) {
- next false if stop_next_down
- next true if @force_add_hidden && line.hidden?
- next true if @force_add_empty && line.empty?
+ yield line
+ end.last&.index
- if @stop_after_kw && end_count > kw_count
- stop_next_down = true
- end
+ if index && index < before_index
+ @before_index = index
+ end
- yield line
- }
- )
+ stop_next = false
+ kw_count = 0
+ end_count = 0
+ index = after_lines.take_while do |line|
+ next false if stop_next
+ next true if @skip_hidden && line.hidden?
+ next true if @skip_empty && line.empty?
+
+ kw_count += 1 if line.is_kw?
+ end_count += 1 if line.is_end?
+ if @stop_after_kw && end_count > kw_count
+ stop_next = true
+ end
+
+ yield line
+ end.last&.index
+ if index && index > after_index
+ @after_index = index
+ end
self
end
- # Scanning is intentionally conservative because
- # we have no way of rolling back an aggressive block (at this time)
- #
- # If a block was stopped for some trivial reason, (like an empty line)
- # but the next line would have caused it to be balanced then we
- # can check that condition and grab just one more line either up or
- # down.
- #
- # For example, below if we're scanning up, line 2 might cause
- # the scanning to stop. This is because empty lines might
- # denote logical breaks where the user intended to chunk code
- # which is a good place to stop and check validity. Unfortunately
- # it also means we might have a "dangling" keyword or end.
- #
- # 1 def bark
- # 2
- # 3 end
- #
- # If lines 2 and 3 are in the block, then when this method is
- # run it would see it is unbalanced, but that acquiring line 1
- # would make it balanced, so that's what it does.
- def lookahead_balance_one_line
+ def capture_neighbor_context
+ lines = []
kw_count = 0
end_count = 0
- lines.each do |line|
+ before_lines.reverse_each do |line|
+ next if line.empty?
+ break if line.indent < @orig_indent
+ next if line.indent != @orig_indent
+
kw_count += 1 if line.is_kw?
end_count += 1 if line.is_end?
+ if kw_count != 0 && kw_count == end_count
+ lines << line
+ break
+ end
+
+ lines << line
end
- return self if kw_count == end_count # nothing to balance
-
- @scanner.commit_if_changed # Rollback point if we don't find anything to optimize
-
- # Try to eat up empty lines
- @scanner.scan(
- up: ->(line, _, _) { line.hidden? || line.empty? },
- down: ->(line, _, _) { line.hidden? || line.empty? }
- )
-
- # More ends than keywords, check if we can balance expanding up
- next_up = @scanner.next_up
- next_down = @scanner.next_down
- case end_count - kw_count
- when 1
- if next_up&.is_kw? && next_up.indent >= @target_indent
- @scanner.scan(
- up: ->(line, _, _) { line == next_up },
- down: ->(line, _, _) { false }
- )
- @scanner.commit_if_changed
+ lines.reverse!
+
+ kw_count = 0
+ end_count = 0
+ after_lines.each do |line|
+ next if line.empty?
+ break if line.indent < @orig_indent
+ next if line.indent != @orig_indent
+
+ kw_count += 1 if line.is_kw?
+ end_count += 1 if line.is_end?
+ if kw_count != 0 && kw_count == end_count
+ lines << line
+ break
end
- when -1
- if next_down&.is_end? && next_down.indent >= @target_indent
- @scanner.scan(
- up: ->(line, _, _) { false },
- down: ->(line, _, _) { line == next_down }
- )
- @scanner.commit_if_changed
+
+ lines << line
+ end
+
+ lines
+ end
+
+ def on_falling_indent
+ last_indent = @orig_indent
+ before_lines.reverse_each do |line|
+ next if line.empty?
+ if line.indent < last_indent
+ yield line
+ last_indent = line.indent
end
end
- # Rollback any uncommitted changes
- @scanner.stash_changes
- self
+ last_indent = @orig_indent
+ after_lines.each do |line|
+ next if line.empty?
+ if line.indent < last_indent
+ yield line
+ last_indent = line.indent
+ end
+ end
+ end
+
+ def scan_neighbors
+ scan_while { |line| line.not_empty? && line.indent >= @orig_indent }
end
- # Finds code lines at the same or greater indentation and adds them
- # to the block
- def scan_neighbors_not_empty
- @target_indent = @orig_indent
- scan_while { |line| line.not_empty? && line.indent >= @target_indent }
+ def next_up
+ @code_lines[before_index.pred]
+ end
+
+ def next_down
+ @code_lines[after_index.next]
end
- # Scan blocks based on indentation of next line above/below block
- #
- # Determines indentaion of the next line above/below the current block.
- #
- # Normally this is called when a block has expanded to capture all "neighbors"
- # at the same (or greater) indentation and needs to expand out. For example
- # the `def/end` lines surrounding a method.
def scan_adjacent_indent
before_after_indent = []
+ before_after_indent << (next_up&.indent || 0)
+ before_after_indent << (next_down&.indent || 0)
- before_after_indent << (@scanner.next_up&.indent || 0)
- before_after_indent << (@scanner.next_down&.indent || 0)
+ indent = before_after_indent.min
+ scan_while { |line| line.not_empty? && line.indent >= indent }
- @target_indent = before_after_indent.min
- scan_while { |line| line.not_empty? && line.indent >= @target_indent }
+ self
+ end
+ def start_at_next_line
+ before_index
+ after_index
+ @before_index -= 1
+ @after_index += 1
self
end
- # Return the currently matched lines as a `CodeBlock`
- #
- # When a `CodeBlock` is created it will gather metadata about
- # itself, so this is not a free conversion. Avoid allocating
- # more CodeBlock's than needed
def code_block
CodeBlock.new(lines: lines)
end
- # Returns the lines matched by the current scan as an
- # array of CodeLines
def lines
- @scanner.lines
+ @code_lines[before_index..after_index]
+ end
+
+ def before_index
+ @before_index ||= @orig_before_index
+ end
+
+ def after_index
+ @after_index ||= @orig_after_index
+ end
+
+ private def before_lines
+ @code_lines[0...before_index] || []
end
- # Manageable rspec errors
- def inspect
- "#<#{self.class}:0x0000123843lol >"
+ private def after_lines
+ @code_lines[after_index.next..-1] || []
end
end
end
diff --git a/lib/syntax_suggest/block_expand.rb b/lib/syntax_suggest/block_expand.rb
index 2751ae2a64..396b2c3a1a 100644
--- a/lib/syntax_suggest/block_expand.rb
+++ b/lib/syntax_suggest/block_expand.rb
@@ -35,121 +35,30 @@ module SyntaxSuggest
@code_lines = code_lines
end
- # Main interface. Expand current indentation, before
- # expanding to a lower indentation
def call(block)
if (next_block = expand_neighbors(block))
- next_block
- else
- expand_indent(block)
+ return next_block
end
+
+ expand_indent(block)
end
- # Expands code to the next lowest indentation
- #
- # For example:
- #
- # 1 def dog
- # 2 print "dog"
- # 3 end
- #
- # If a block starts on line 2 then it has captured all it's "neighbors" (code at
- # the same indentation or higher). To continue expanding, this block must capture
- # lines one and three which are at a different indentation level.
- #
- # This method allows fully expanded blocks to decrease their indentation level (so
- # they can expand to capture more code up and down). It does this conservatively
- # as there's no undo (currently).
def expand_indent(block)
- now = AroundBlockScan.new(code_lines: @code_lines, block: block)
- .force_add_hidden
+ AroundBlockScan.new(code_lines: @code_lines, block: block)
+ .skip(:hidden?)
.stop_after_kw
.scan_adjacent_indent
-
- now.lookahead_balance_one_line
-
- now.code_block
+ .code_block
end
- # A neighbor is code that is at or above the current indent line.
- #
- # First we build a block with all neighbors. If we can't go further
- # then we decrease the indentation threshold and expand via indentation
- # i.e. `expand_indent`
- #
- # Handles two general cases.
- #
- # ## Case #1: Check code inside of methods/classes/etc.
- #
- # It's important to note, that not everything in a given indentation level can be parsed
- # as valid code even if it's part of valid code. For example:
- #
- # 1 hash = {
- # 2 name: "richard",
- # 3 dog: "cinco",
- # 4 }
- #
- # In this case lines 2 and 3 will be neighbors, but they're invalid until `expand_indent`
- # is called on them.
- #
- # When we are adding code within a method or class (at the same indentation level),
- # use the empty lines to denote the programmer intended logical chunks.
- # Stop and check each one. For example:
- #
- # 1 def dog
- # 2 print "dog"
- # 3
- # 4 hash = {
- # 5 end
- #
- # If we did not stop parsing at empty newlines then the block might mistakenly grab all
- # the contents (lines 2, 3, and 4) and report them as being problems, instead of only
- # line 4.
- #
- # ## Case #2: Expand/grab other logical blocks
- #
- # Once the search algorithm has converted all lines into blocks at a given indentation
- # it will then `expand_indent`. Once the blocks that generates are expanded as neighbors
- # we then begin seeing neighbors being other logical blocks i.e. a block's neighbors
- # may be another method or class (something with keywords/ends).
- #
- # For example:
- #
- # 1 def bark
- # 2
- # 3 end
- # 4
- # 5 def sit
- # 6 end
- #
- # In this case if lines 4, 5, and 6 are in a block when it tries to expand neighbors
- # it will expand up. If it stops after line 2 or 3 it may cause problems since there's a
- # valid kw/end pair, but the block will be checked without it.
- #
- # We try to resolve this edge case with `lookahead_balance_one_line` below.
def expand_neighbors(block)
- now = AroundBlockScan.new(code_lines: @code_lines, block: block)
-
- # Initial scan
- now
- .force_add_hidden
+ expanded_lines = AroundBlockScan.new(code_lines: @code_lines, block: block)
+ .skip(:hidden?)
.stop_after_kw
- .scan_neighbors_not_empty
-
- # Slurp up empties
- now
- .scan_while { |line| line.empty? }
-
- # If next line is kw and it will balance us, take it
- expanded_lines = now
- .lookahead_balance_one_line
+ .scan_neighbors
+ .scan_while { |line| line.empty? } # Slurp up empties
.lines
- # Don't allocate a block if it won't be used
- #
- # If nothing was taken, return nil to indicate that status
- # used in `def call` to determine if
- # we need to expand up/out (`expand_indent`)
if block.lines == expanded_lines
nil
else
@@ -157,7 +66,7 @@ module SyntaxSuggest
end
end
- # Manageable rspec errors
+ # Managable rspec errors
def inspect
"#<SyntaxSuggest::CodeBlock:0x0000123843lol >"
end
diff --git a/lib/syntax_suggest/capture/before_after_keyword_ends.rb b/lib/syntax_suggest/capture/before_after_keyword_ends.rb
deleted file mode 100644
index f53c57a4d1..0000000000
--- a/lib/syntax_suggest/capture/before_after_keyword_ends.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-# frozen_string_literal: true
-
-module SyntaxSuggest
- module Capture
- # Shows surrounding kw/end pairs
- #
- # The purpose of showing these extra pairs is due to cases
- # of ambiguity when only one visible line is matched.
- #
- # For example:
- #
- # 1 class Dog
- # 2 def bark
- # 4 def eat
- # 5 end
- # 6 end
- #
- # In this case either line 2 could be missing an `end` or
- # line 4 was an extra line added by mistake (it happens).
- #
- # When we detect the above problem it shows the issue
- # as only being on line 2
- #
- # 2 def bark
- #
- # Showing "neighbor" keyword pairs gives extra context:
- #
- # 2 def bark
- # 4 def eat
- # 5 end
- #
- #
- # Example:
- #
- # lines = BeforeAfterKeywordEnds.new(
- # block: block,
- # code_lines: code_lines
- # ).call()
- #
- class BeforeAfterKeywordEnds
- def initialize(code_lines:, block:)
- @scanner = ScanHistory.new(code_lines: code_lines, block: block)
- @original_indent = block.current_indent
- end
-
- def call
- lines = []
-
- @scanner.scan(
- up: ->(line, kw_count, end_count) {
- next true if line.empty?
- break if line.indent < @original_indent
- next true if line.indent != @original_indent
-
- # If we're going up and have one complete kw/end pair, stop
- if kw_count != 0 && kw_count == end_count
- lines << line
- break
- end
-
- lines << line if line.is_kw? || line.is_end?
- true
- },
- down: ->(line, kw_count, end_count) {
- next true if line.empty?
- break if line.indent < @original_indent
- next true if line.indent != @original_indent
-
- # if we're going down and have one complete kw/end pair,stop
- if kw_count != 0 && kw_count == end_count
- lines << line
- break
- end
-
- lines << line if line.is_kw? || line.is_end?
- true
- }
- )
- @scanner.stash_changes
-
- lines
- end
- end
- end
-end
diff --git a/lib/syntax_suggest/capture/falling_indent_lines.rb b/lib/syntax_suggest/capture/falling_indent_lines.rb
deleted file mode 100644
index 1e046b2ba5..0000000000
--- a/lib/syntax_suggest/capture/falling_indent_lines.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-# frozen_string_literal: true
-
-module SyntaxSuggest
- module Capture
- # Shows the context around code provided by "falling" indentation
- #
- # If this is the original code lines:
- #
- # class OH
- # def hello
- # it "foo" do
- # end
- # end
- #
- # And this is the line that is captured
- #
- # it "foo" do
- #
- # It will yield its surrounding context:
- #
- # class OH
- # def hello
- # end
- # end
- #
- # Example:
- #
- # FallingIndentLines.new(
- # block: block,
- # code_lines: @code_lines
- # ).call do |line|
- # @lines_to_output << line
- # end
- #
- class FallingIndentLines
- def initialize(code_lines:, block:)
- @lines = nil
- @scanner = ScanHistory.new(code_lines: code_lines, block: block)
- @original_indent = block.current_indent
- end
-
- def call(&yieldable)
- last_indent_up = @original_indent
- last_indent_down = @original_indent
-
- @scanner.commit_if_changed
- @scanner.scan(
- up: ->(line, _, _) {
- next true if line.empty?
-
- if line.indent < last_indent_up
- yieldable.call(line)
- last_indent_up = line.indent
- end
- true
- },
- down: ->(line, _, _) {
- next true if line.empty?
-
- if line.indent < last_indent_down
- yieldable.call(line)
- last_indent_down = line.indent
- end
- true
- }
- )
- @scanner.stash_changes
- end
- end
- end
-end
diff --git a/lib/syntax_suggest/capture_code_context.rb b/lib/syntax_suggest/capture_code_context.rb
index 1f232cfae3..7d6a550612 100644
--- a/lib/syntax_suggest/capture_code_context.rb
+++ b/lib/syntax_suggest/capture_code_context.rb
@@ -1,14 +1,6 @@
# frozen_string_literal: true
module SyntaxSuggest
- module Capture
- end
-end
-
-require_relative "capture/falling_indent_lines"
-require_relative "capture/before_after_keyword_ends"
-
-module SyntaxSuggest
# Turns a "invalid block(s)" into useful context
#
# There are three main phases in the algorithm:
@@ -26,7 +18,7 @@ module SyntaxSuggest
# they can't add extra data that's not present.
#
# In the case of known ambiguious cases, this class adds context
- # back to the ambiguity so the programmer has full information.
+ # back to the ambiguitiy so the programmer has full information.
#
# Beyond handling these ambiguities, it also captures surrounding
# code context information:
@@ -63,10 +55,6 @@ module SyntaxSuggest
capture_falling_indent(block)
end
- sorted_lines
- end
-
- def sorted_lines
@lines_to_output.select!(&:not_empty?)
@lines_to_output.uniq!
@lines_to_output.sort!
@@ -88,11 +76,12 @@ module SyntaxSuggest
# end
# end
#
+ #
def capture_falling_indent(block)
- Capture::FallingIndentLines.new(
+ AroundBlockScan.new(
block: block,
code_lines: @code_lines
- ).call do |line|
+ ).on_falling_indent do |line|
@lines_to_output << line
end
end
@@ -127,10 +116,9 @@ module SyntaxSuggest
def capture_before_after_kws(block)
return unless block.visible_lines.count == 1
- around_lines = Capture::BeforeAfterKeywordEnds.new(
- code_lines: @code_lines,
- block: block
- ).call
+ around_lines = AroundBlockScan.new(code_lines: @code_lines, block: block)
+ .start_at_next_line
+ .capture_neighbor_context
around_lines -= block.lines
diff --git a/lib/syntax_suggest/clean_document.rb b/lib/syntax_suggest/clean_document.rb
index 2790ccae86..b572189259 100644
--- a/lib/syntax_suggest/clean_document.rb
+++ b/lib/syntax_suggest/clean_document.rb
@@ -47,9 +47,9 @@ module SyntaxSuggest
# ## Heredocs
#
# A heredoc is an way of defining a multi-line string. They can cause many
- # problems. If left as a single line, the parser would try to parse the contents
+ # problems. If left as a single line, Ripper would try to parse the contents
# as ruby code rather than as a string. Even without this problem, we still
- # hit an issue with indentation:
+ # hit an issue with indentation
#
# 1 foo = <<~HEREDOC
# 2 "Be yourself; everyone else is already taken.""
@@ -110,7 +110,7 @@ module SyntaxSuggest
@document.join
end
- # Remove comments
+ # Remove comments and whitespace only lines
#
# replace with empty newlines
#
@@ -155,10 +155,8 @@ module SyntaxSuggest
# ).to eq(2)
#
def clean_sweep(source:)
- # Match comments, but not HEREDOC strings with #{variable} interpolation
- # https://rubular.com/r/HPwtW9OYxKUHXQ
source.lines.map do |line|
- if line.match?(/^\s*#([^{].*|)$/)
+ if line.match?(/^\s*(#[^{].*)?$/) # https://rubular.com/r/LLE10D8HKMkJvs
$/
else
line
@@ -224,7 +222,7 @@ module SyntaxSuggest
#
def join_consecutive!
consecutive_groups = @document.select(&:ignore_newline_not_beg?).map do |code_line|
- take_while_including(code_line.index..) do |line|
+ take_while_including(code_line.index..-1) do |line|
line.ignore_newline_not_beg?
end
end
@@ -245,7 +243,7 @@ module SyntaxSuggest
# expect(lines[1].to_s).to eq("")
def join_trailing_slash!
trailing_groups = @document.select(&:trailing_slash?).map do |code_line|
- take_while_including(code_line.index..) { |x| x.trailing_slash? }
+ take_while_including(code_line.index..-1) { |x| x.trailing_slash? }
end
join_groups(trailing_groups)
self
@@ -267,7 +265,7 @@ module SyntaxSuggest
groups.each do |lines|
line = lines.first
- # Handle the case of multiple groups in a row
+ # Handle the case of multiple groups in a a row
# if one is already replaced, move on
next if @document[line.index].empty?
@@ -279,7 +277,7 @@ module SyntaxSuggest
)
# Hide the rest of the lines
- lines[1..].each do |line|
+ lines[1..-1].each do |line|
# The above lines already have newlines in them, if add more
# then there will be double newline, use an empty line instead
@document[line.index] = CodeLine.new(line: "", index: line.index, lex: [])
@@ -293,7 +291,7 @@ module SyntaxSuggest
# Like `take_while` except when it stops
# iterating, it also returns the line
# that caused it to stop
- def take_while_including(range = 0..)
+ def take_while_including(range = 0..-1)
take_next_and_stop = false
@document[range].take_while do |line|
next if take_next_and_stop
diff --git a/lib/syntax_suggest/code_block.rb b/lib/syntax_suggest/code_block.rb
index d842890300..61e7986da4 100644
--- a/lib/syntax_suggest/code_block.rb
+++ b/lib/syntax_suggest/code_block.rb
@@ -81,7 +81,7 @@ module SyntaxSuggest
# lines then the result cannot be invalid
#
# That means there's no reason to re-check all
- # lines with the parser (which is expensive).
+ # lines with ripper (which is expensive).
# Benchmark in commit message
@valid = if lines.all? { |l| l.hidden? || l.empty? }
true
diff --git a/lib/syntax_suggest/code_frontier.rb b/lib/syntax_suggest/code_frontier.rb
index 0f870d0df0..8e93b32514 100644
--- a/lib/syntax_suggest/code_frontier.rb
+++ b/lib/syntax_suggest/code_frontier.rb
@@ -117,7 +117,7 @@ module SyntaxSuggest
if ENV["SYNTAX_SUGGEST_DEBUG"]
puts "```"
- puts @queue.peek
+ puts @queue.peek.to_s
puts "```"
puts " @frontier indent: #{frontier_indent}"
puts " @unvisited indent: #{unvisited_indent}"
diff --git a/lib/syntax_suggest/code_line.rb b/lib/syntax_suggest/code_line.rb
index 58197e95d0..dc738ab128 100644
--- a/lib/syntax_suggest/code_line.rb
+++ b/lib/syntax_suggest/code_line.rb
@@ -48,10 +48,12 @@ module SyntaxSuggest
strip_line = line.dup
strip_line.lstrip!
- @indent = if (@empty = strip_line.empty?)
- line.length - 1 # Newline removed from strip_line is not "whitespace"
+ if strip_line.empty?
+ @empty = true
+ @indent = 0
else
- line.length - strip_line.length
+ @empty = false
+ @indent = line.length - strip_line.length
end
set_kw_end
@@ -180,19 +182,12 @@ module SyntaxSuggest
# EOM
# expect(lines.first.trailing_slash?).to eq(true)
#
- if SyntaxSuggest.use_prism_parser?
- def trailing_slash?
- last = @lex.last
- last&.type == :on_tstring_end
- end
- else
- def trailing_slash?
- last = @lex.last
- return false unless last
- return false unless last.type == :on_sp
+ def trailing_slash?
+ last = @lex.last
+ return false unless last
+ return false unless last.type == :on_sp
- last.token == TRAILING_SLASH
- end
+ last.token == TRAILING_SLASH
end
# Endless method detection
diff --git a/lib/syntax_suggest/code_search.rb b/lib/syntax_suggest/code_search.rb
index 7628dcd131..2a86dfea90 100644
--- a/lib/syntax_suggest/code_search.rb
+++ b/lib/syntax_suggest/code_search.rb
@@ -43,7 +43,7 @@ module SyntaxSuggest
def initialize(source, record_dir: DEFAULT_VALUE)
record_dir = if record_dir == DEFAULT_VALUE
- (ENV["SYNTAX_SUGGEST_RECORD_DIR"] || ENV["SYNTAX_SUGGEST_DEBUG"]) ? "tmp" : nil
+ ENV["SYNTAX_SUGGEST_RECORD_DIR"] || ENV["SYNTAX_SUGGEST_DEBUG"] ? "tmp" : nil
else
record_dir
end
@@ -73,7 +73,7 @@ module SyntaxSuggest
if ENV["SYNTAX_SUGGEST_DEBUG"]
puts "\n\n==== #{filename} ===="
puts "\n```#{block.starts_at}..#{block.ends_at}"
- puts block
+ puts block.to_s
puts "```"
puts " block indent: #{block.current_indent}"
end
diff --git a/lib/syntax_suggest/core_ext.rb b/lib/syntax_suggest/core_ext.rb
index c299627bb7..aed93e129c 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
@@ -45,8 +45,6 @@ if SyntaxError.method_defined?(:detailed_message)
)
annotation = io.string
- annotation += "\n" unless annotation.end_with?("\n")
-
annotation + message
else
message
@@ -68,13 +66,9 @@ if SyntaxError.method_defined?(:detailed_message)
else
autoload :Pathname, "pathname"
- #--
# Monkey patch kernel to ensure that all `require` calls call the same
# method
- #++
module Kernel
- # :stopdoc:
-
module_function
alias_method :syntax_suggest_original_require, :require
diff --git a/lib/syntax_suggest/display_invalid_blocks.rb b/lib/syntax_suggest/display_invalid_blocks.rb
index 5e79b3a262..32ec0021a3 100644
--- a/lib/syntax_suggest/display_invalid_blocks.rb
+++ b/lib/syntax_suggest/display_invalid_blocks.rb
@@ -14,7 +14,7 @@ module SyntaxSuggest
@filename = filename
@code_lines = code_lines
- @terminal = (terminal == DEFAULT_VALUE) ? io.isatty : terminal
+ @terminal = terminal == DEFAULT_VALUE ? io.isatty : terminal
end
def document_ok?
diff --git a/lib/syntax_suggest/explain_syntax.rb b/lib/syntax_suggest/explain_syntax.rb
index 0d80c4d869..142ed2e269 100644
--- a/lib/syntax_suggest/explain_syntax.rb
+++ b/lib/syntax_suggest/explain_syntax.rb
@@ -2,21 +2,7 @@
require_relative "left_right_lex_count"
-if !SyntaxSuggest.use_prism_parser?
- require_relative "ripper_errors"
-end
-
module SyntaxSuggest
- class GetParseErrors
- def self.errors(source)
- if SyntaxSuggest.use_prism_parser?
- Prism.parse(source).errors.map(&:message)
- else
- RipperErrors.new(source).call.errors
- end
- end
- end
-
# Explains syntax errors based on their source
#
# example:
@@ -29,8 +15,8 @@ module SyntaxSuggest
# # => "Unmatched keyword, missing `end' ?"
#
# When the error cannot be determined by lexical counting
- # then the parser is run against the input and the raw
- # errors are returned.
+ # then ripper is run against the input and the raw ripper
+ # errors returned.
#
# Example:
#
@@ -105,10 +91,10 @@ module SyntaxSuggest
# Returns an array of syntax error messages
#
# If no missing pairs are found it falls back
- # on the original error messages
+ # on the original ripper error messages
def errors
if missing.empty?
- return GetParseErrors.errors(@code_lines.map(&:original).join).uniq
+ return RipperErrors.new(@code_lines.map(&:original).join).call.errors
end
missing.map { |miss| why(miss) }
diff --git a/lib/syntax_suggest/lex_all.rb b/lib/syntax_suggest/lex_all.rb
index c16fbb52d3..132cba9f5d 100644
--- a/lib/syntax_suggest/lex_all.rb
+++ b/lib/syntax_suggest/lex_all.rb
@@ -3,53 +3,34 @@
module SyntaxSuggest
# Ripper.lex is not guaranteed to lex the entire source document
#
- # This class guarantees the whole document is lex-ed by iteratively
- # lexing the document where ripper stopped.
- #
- # Prism likely doesn't have the same problem. Once ripper support is removed
- # we can likely reduce the complexity here if not remove the whole concept.
- #
- # Example usage:
- #
- # lex = LexAll.new(source: source)
- # lex.each do |value|
- # puts value.line
- # end
+ # lex = LexAll.new(source: source)
+ # lex.each do |value|
+ # puts value.line
+ # end
class LexAll
include Enumerable
def initialize(source:, source_lines: nil)
- @lex = self.class.lex(source, 1)
- lineno = @lex.last[0][0] + 1
+ @lex = Ripper::Lexer.new(source, "-", 1).parse.sort_by(&:pos)
+ lineno = @lex.last.pos.first + 1
source_lines ||= source.lines
last_lineno = source_lines.length
until lineno >= last_lineno
- lines = source_lines[lineno..]
+ lines = source_lines[lineno..-1]
@lex.concat(
- self.class.lex(lines.join, lineno + 1)
+ Ripper::Lexer.new(lines.join, "-", lineno + 1).parse.sort_by(&:pos)
)
-
- lineno = @lex.last[0].first + 1
+ lineno = @lex.last.pos.first + 1
end
last_lex = nil
@lex.map! { |elem|
- last_lex = LexValue.new(elem[0].first, elem[1], elem[2], elem[3], last_lex)
+ last_lex = LexValue.new(elem.pos.first, elem.event, elem.tok, elem.state, last_lex)
}
end
- if SyntaxSuggest.use_prism_parser?
- def self.lex(source, line_number)
- Prism.lex_compat(source, line: line_number).value.sort_by { |values| values[0] }
- end
- else
- def self.lex(source, line_number)
- Ripper::Lexer.new(source, "-", line_number).parse.sort_by(&:pos)
- end
- end
-
def to_a
@lex
end
diff --git a/lib/syntax_suggest/lex_value.rb b/lib/syntax_suggest/lex_value.rb
index b46a332772..008cc105b5 100644
--- a/lib/syntax_suggest/lex_value.rb
+++ b/lib/syntax_suggest/lex_value.rb
@@ -28,7 +28,7 @@ module SyntaxSuggest
@is_end = false
@is_kw = false
return if type != :on_kw
-
+ #
return if last_lex && last_lex.fname? # https://github.com/ruby/ruby/commit/776759e300e4659bb7468e2b97c8c2d4359a2953
case token
diff --git a/lib/syntax_suggest/parse_blocks_from_indent_line.rb b/lib/syntax_suggest/parse_blocks_from_indent_line.rb
index 39dfca55d2..d1071732fe 100644
--- a/lib/syntax_suggest/parse_blocks_from_indent_line.rb
+++ b/lib/syntax_suggest/parse_blocks_from_indent_line.rb
@@ -8,7 +8,7 @@ module SyntaxSuggest
# grabbing one that contains only an "end". In this example:
#
# def dog
- # begonn # misspelled `begin`
+ # begonn # mispelled `begin`
# puts "bark"
# end
# end
@@ -36,8 +36,8 @@ module SyntaxSuggest
# Builds blocks from bottom up
def each_neighbor_block(target_line)
scan = AroundBlockScan.new(code_lines: code_lines, block: CodeBlock.new(lines: target_line))
- .force_add_empty
- .force_add_hidden
+ .skip(:empty?)
+ .skip(:hidden?)
.scan_while { |line| line.indent >= target_line.indent }
neighbors = scan.code_block.lines
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/syntax_suggest/ripper_errors.rb b/lib/syntax_suggest/ripper_errors.rb
index 4e2bc90948..48eb206e48 100644
--- a/lib/syntax_suggest/ripper_errors.rb
+++ b/lib/syntax_suggest/ripper_errors.rb
@@ -1,10 +1,7 @@
# frozen_string_literal: true
module SyntaxSuggest
- # Capture parse errors from Ripper
- #
- # Prism returns the errors with their messages, but Ripper
- # does not. To get them we must make a custom subclass.
+ # Capture parse errors from ripper
#
# Example:
#
diff --git a/lib/syntax_suggest/scan_history.rb b/lib/syntax_suggest/scan_history.rb
deleted file mode 100644
index dc36e6ba2e..0000000000
--- a/lib/syntax_suggest/scan_history.rb
+++ /dev/null
@@ -1,134 +0,0 @@
-# frozen_string_literal: true
-
-module SyntaxSuggest
- # Scans up/down from the given block
- #
- # You can try out a change, stash it, or commit it to save for later
- #
- # Example:
- #
- # scanner = ScanHistory.new(code_lines: code_lines, block: block)
- # scanner.scan(
- # up: ->(_, _, _) { true },
- # down: ->(_, _, _) { true }
- # )
- # scanner.changed? # => true
- # expect(scanner.lines).to eq(code_lines)
- #
- # scanner.stash_changes
- #
- # expect(scanner.lines).to_not eq(code_lines)
- class ScanHistory
- attr_reader :before_index, :after_index
-
- def initialize(code_lines:, block:)
- @code_lines = code_lines
- @history = [block]
- refresh_index
- end
-
- def commit_if_changed
- if changed?
- @history << CodeBlock.new(lines: @code_lines[before_index..after_index])
- end
-
- self
- end
-
- # Discards any changes that have not been committed
- def stash_changes
- refresh_index
- self
- end
-
- # Discard changes that have not been committed and revert the last commit
- #
- # Cannot revert the first commit
- def revert_last_commit
- if @history.length > 1
- @history.pop
- refresh_index
- end
-
- self
- end
-
- def changed?
- @before_index != current.lines.first.index ||
- @after_index != current.lines.last.index
- end
-
- # Iterates up and down
- #
- # Returns line, kw_count, end_count for each iteration
- def scan(up:, down:)
- kw_count = 0
- end_count = 0
-
- up_index = before_lines.reverse_each.take_while do |line|
- kw_count += 1 if line.is_kw?
- end_count += 1 if line.is_end?
- up.call(line, kw_count, end_count)
- end.last&.index
-
- kw_count = 0
- end_count = 0
-
- down_index = after_lines.each.take_while do |line|
- kw_count += 1 if line.is_kw?
- end_count += 1 if line.is_end?
- down.call(line, kw_count, end_count)
- end.last&.index
-
- @before_index = if up_index && up_index < @before_index
- up_index
- else
- @before_index
- end
-
- @after_index = if down_index && down_index > @after_index
- down_index
- else
- @after_index
- end
-
- self
- end
-
- def next_up
- return nil if @before_index <= 0
-
- @code_lines[@before_index - 1]
- end
-
- def next_down
- return nil if @after_index >= @code_lines.length
-
- @code_lines[@after_index + 1]
- end
-
- def lines
- @code_lines[@before_index..@after_index]
- end
-
- private def before_lines
- @code_lines[0...@before_index] || []
- end
-
- # Returns an array of all the CodeLines that exist after
- # the currently scanned block
- private def after_lines
- @code_lines[@after_index.next..] || []
- end
-
- private def current
- @history.last
- end
-
- private def refresh_index
- @before_index = current.lines.first.index
- @after_index = current.lines.last.index
- self
- end
- end
-end
diff --git a/lib/syntax_suggest/syntax_suggest.gemspec b/lib/syntax_suggest/syntax_suggest.gemspec
index 756a85bf63..73b25c6a5f 100644
--- a/lib/syntax_suggest/syntax_suggest.gemspec
+++ b/lib/syntax_suggest/syntax_suggest.gemspec
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
spec.description = 'When you get an "unexpected end" in your syntax this gem helps you find it'
spec.homepage = "https://github.com/ruby/syntax_suggest.git"
spec.license = "MIT"
- spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = "https://github.com/ruby/syntax_suggest.git"
@@ -27,6 +27,6 @@ Gem::Specification.new do |spec|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets)/}) }
end
spec.bindir = "exe"
- spec.executables = ["syntax_suggest"]
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
end
diff --git a/lib/syntax_suggest/version.rb b/lib/syntax_suggest/version.rb
index d5eff2a17a..d9ea5200e6 100644
--- a/lib/syntax_suggest/version.rb
+++ b/lib/syntax_suggest/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module SyntaxSuggest
- VERSION = "2.0.1"
+ VERSION = "1.0.2"
end
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 cf6085192b..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.1"
-
# 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,57 +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
- alias to_s inspect
-
- 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..e4b5502f28 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.1"
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..43c4d802e5 100644
--- a/lib/time.rb
+++ b/lib/time.rb
@@ -25,9 +25,6 @@ require 'date'
# :startdoc:
class Time
-
- VERSION = "0.3.0"
-
class << Time
#
@@ -512,8 +509,8 @@ class Time
(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+
(\d{2,})\s+
(\d{2})\s*
- :\s*(\d{2})
- (?:\s*:\s*(\d\d))?\s+
+ :\s*(\d{2})\s*
+ (?::\s*(\d{2}))?\s+
([+-]\d{4}|
UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-IK-Z])/ix =~ date
# Since RFC 2822 permit comments, the regexp has no right anchor.
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 b60292765a..ca38bec7ec 100644
--- a/lib/uri/common.rb
+++ b/lib/uri/common.rb
@@ -19,8 +19,6 @@ 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
@@ -70,32 +68,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)]
@@ -106,21 +88,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
@@ -151,49 +121,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>
@@ -238,7 +254,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
@@ -275,7 +291,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
@@ -298,86 +314,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
@@ -402,104 +372,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?
@@ -520,39 +419,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 = []
@@ -831,15 +713,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 2c0a88da5d..69698c4e2d 100644
--- a/lib/uri/generic.rb
+++ b/lib/uri/generic.rb
@@ -1133,16 +1133,17 @@ module URI
base.fragment=(nil)
# RFC2396, Section 5.2, 4)
- 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))
+ 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
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
@@ -1375,7 +1376,6 @@ module URI
end
str
end
- alias to_str to_s
#
# Compares two URIs.
diff --git a/lib/uri/rfc2396_parser.rb b/lib/uri/rfc2396_parser.rb
index 00c66cf042..76a8f99fd4 100644
--- a/lib/uri/rfc2396_parser.rb
+++ b/lib/uri/rfc2396_parser.rb
@@ -497,8 +497,8 @@ module URI
ret = {}
# for URI::split
- ret[:ABS_URI] = Regexp.new('\A\s*+' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
- ret[:REL_URI] = Regexp.new('\A\s*+' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
+ ret[:ABS_URI] = Regexp.new('\A\s*' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
+ ret[:REL_URI] = Regexp.new('\A\s*' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
# for URI::extract
ret[:URI_REF] = Regexp.new(pattern[:URI_REF])
diff --git a/lib/uri/rfc3986_parser.rb b/lib/uri/rfc3986_parser.rb
index 092a1ac89d..f3816d9ae5 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,15 +92,15 @@ 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],
- PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\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 962f09a3e6..a9643ef8bc 100644
--- a/lib/uri/version.rb
+++ b/lib/uri/version.rb
@@ -1,6 +1,6 @@
module URI
# :stopdoc:
- VERSION_CODE = '001302'.freeze
+ VERSION_CODE = '001200'.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/bundle b/libexec/bundle
index 92387bc2cf..eaf2246bc0 100755
--- a/libexec/bundle
+++ b/libexec/bundle
@@ -10,20 +10,37 @@ end
base_path = File.expand_path("../lib", __dir__)
if File.exist?(base_path)
- $LOAD_PATH.unshift(base_path)
+ require_relative "../lib/bundler"
+else
+ require "bundler"
end
-require "bundler"
+if Gem.rubygems_version < Gem::Version.new("3.2.3") && Gem.ruby_version < Gem::Version.new("2.7.a") && !ENV["BUNDLER_NO_OLD_RUBYGEMS_WARNING"]
+ Bundler.ui.warn \
+ "Your RubyGems version (#{Gem::VERSION}) has a bug that prevents " \
+ "`required_ruby_version` from working for Bundler. Any scripts that use " \
+ "`gem install bundler` will break as soon as Bundler drops support for " \
+ "your Ruby version. Please upgrade RubyGems to avoid future breakage " \
+ "and silence this warning by running `gem update --system 3.2.3`"
+end
-require "bundler/friendly_errors"
+if File.exist?(base_path)
+ require_relative "../lib/bundler/friendly_errors"
+else
+ require "bundler/friendly_errors"
+end
Bundler.with_friendly_errors do
- require "bundler/cli"
+ if File.exist?(base_path)
+ require_relative "../lib/bundler/cli"
+ else
+ require "bundler/cli"
+ end
# Allow any command to use --help flag to show help for that command
help_flags = %w[--help -h]
help_flag_used = ARGV.any? {|a| help_flags.include? a }
args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV
- Bundler::CLI.start(args, debug: true)
+ Bundler::CLI.start(args, :debug => true)
end
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/libexec/syntax_suggest b/libexec/syntax_suggest
index 3dc8eb94d1..e4a0b0b658 100755
--- a/libexec/syntax_suggest
+++ b/libexec/syntax_suggest
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
-require "syntax_suggest/api"
+require_relative "../lib/syntax_suggest/api"
SyntaxSuggest::Cli.new(
argv: ARGV
diff --git a/load.c b/load.c
index 721a331ced..282bebdb62 100644
--- a/load.c
+++ b/load.c
@@ -8,9 +8,8 @@
#include "internal/dir.h"
#include "internal/error.h"
#include "internal/file.h"
-#include "internal/hash.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"
@@ -19,27 +18,12 @@
#include "ruby/encoding.h"
#include "ruby/util.h"
-static VALUE ruby_dln_libmap;
+static VALUE ruby_dln_librefs;
#define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
-#if SIZEOF_VALUE <= SIZEOF_LONG
-# define SVALUE2NUM(x) LONG2NUM((long)(x))
-# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LONG(x)
-#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
-# define SVALUE2NUM(x) LL2NUM((LONG_LONG)(x))
-# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LL(x)
-#else
-# error Need integer for VALUE
-#endif
-
-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
@@ -180,12 +164,6 @@ get_loaded_features_realpaths(rb_vm_t *vm)
}
static VALUE
-get_loaded_features_realpath_map(rb_vm_t *vm)
-{
- return vm->loaded_features_realpath_map;
-}
-
-static VALUE
get_LOADED_FEATURES(ID _x, VALUE *_y)
{
return get_loaded_features(GET_VM());
@@ -371,13 +349,6 @@ loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
return ST_DELETE;
}
-void
-rb_free_loaded_features_index(rb_vm_t *vm)
-{
- st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
- st_free_table(vm->loaded_features_index);
-}
-
static st_table *
get_loaded_features_index(rb_vm_t *vm)
{
@@ -390,16 +361,13 @@ get_loaded_features_index(rb_vm_t *vm)
st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
VALUE realpaths = vm->loaded_features_realpaths;
- VALUE realpath_map = vm->loaded_features_realpath_map;
- VALUE previous_realpath_map = rb_hash_dup(realpath_map);
rb_hash_clear(realpaths);
- rb_hash_clear(realpath_map);
features = vm->loaded_features;
for (i = 0; i < RARRAY_LEN(features); i++) {
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));
@@ -410,14 +378,9 @@ get_loaded_features_index(rb_vm_t *vm)
long j = RARRAY_LEN(features);
for (i = 0; i < j; i++) {
VALUE as_str = rb_ary_entry(features, i);
- VALUE realpath = rb_hash_aref(previous_realpath_map, as_str);
- if (NIL_P(realpath)) {
- realpath = rb_check_realpath(Qnil, as_str, NULL);
- if (NIL_P(realpath)) realpath = as_str;
- realpath = rb_fstring(realpath);
- }
- rb_hash_aset(realpaths, realpath, Qtrue);
- rb_hash_aset(realpath_map, as_str, realpath);
+ VALUE realpath = rb_check_realpath(Qnil, as_str, NULL);
+ if (NIL_P(realpath)) realpath = as_str;
+ rb_hash_aset(realpaths, rb_fstring(realpath), Qtrue);
}
}
return vm->loaded_features_index;
@@ -498,12 +461,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)
{
@@ -596,7 +553,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 && !rb_is_absolute_path(feature)) {
+ if (!expanded) {
struct loaded_feature_searching fs;
fs.name = feature;
fs.len = len;
@@ -698,14 +655,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);
}
@@ -718,57 +675,23 @@ 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)
{
const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
if (!iseq) {
- if (*rb_ruby_prism_ptr()) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- pm_string_mapped_init(&input, RSTRING_PTR(fname));
- pm_options_filepath_set(&options, RSTRING_PTR(fname));
-
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), &options);
-
- iseq = rb_iseq_new_main_prism(&input, &options, fname);
-
- pm_string_free(&input);
- pm_options_free(&options);
- }
- else {
- rb_execution_context_t *ec = GET_EC();
- VALUE v = rb_vm_push_frame_fname(ec, fname);
- rb_ast_t *ast;
- 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);
- rb_ast_dispose(ast);
- rb_vm_pop_frame(ec);
- RB_GC_GUARD(v);
- }
+ rb_execution_context_t *ec = GET_EC();
+ VALUE v = rb_vm_push_frame_fname(ec, fname);
+ rb_ast_t *ast;
+ VALUE parser = rb_parser_new();
+ rb_parser_set_context(parser, NULL, FALSE);
+ ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
+ iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
+ fname, rb_realpath_internal(Qnil, fname, 1), NULL);
+ rb_ast_dispose(ast);
+ rb_vm_pop_frame(ec);
+ RB_GC_GUARD(v);
}
rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
rb_iseq_eval(iseq);
@@ -927,8 +850,7 @@ load_lock(rb_vm_t *vm, const char *ftptr, bool warn)
st_insert(loading_tbl, (st_data_t)ftptr, data);
return (char *)ftptr;
}
-
- if (warn && rb_thread_shield_owned((VALUE)data)) {
+ if (warn) {
VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
rb_backtrace_each(rb_str_append, warning);
rb_warning("%"PRIsVALUE, warning);
@@ -970,7 +892,6 @@ load_unlock(rb_vm_t *vm, const char *ftptr, int done)
}
}
-static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
/*
* call-seq:
@@ -985,14 +906,15 @@ static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
* If the filename starts with './' or '../', resolution is based on Dir.pwd.
*
* If the filename has the extension ".rb", it is loaded as a source file; if
- * the extension is ".so", ".o", or the default shared library extension on
- * the current platform, Ruby loads the shared library as a Ruby extension.
- * Otherwise, Ruby tries adding ".rb", ".so", and so on to the name until
- * found. If the file named cannot be found, a LoadError will be raised.
+ * the extension is ".so", ".o", or ".dll", or the default shared library
+ * extension on the current platform, Ruby loads the shared library as a
+ * Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on
+ * to the name until found. If the file named cannot be found, a LoadError
+ * will be raised.
*
- * For Ruby extensions the filename given may use ".so" or ".o". For example,
- * on macOS the socket extension is "socket.bundle" and
- * <code>require 'socket.so'</code> will load the socket extension.
+ * For Ruby extensions the filename given may use any shared library
+ * extension. For example, on Linux the socket extension is "socket.so" and
+ * <code>require 'socket.dll'</code> will load the socket extension.
*
* The absolute path of the loaded file is added to
* <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
@@ -1032,7 +954,7 @@ rb_f_require_relative(VALUE obj, VALUE fname)
rb_loaderror("cannot infer basepath");
}
base = rb_file_dirname(base);
- return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
+ return rb_require_string(rb_file_absolute_path(fname, base));
}
typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
@@ -1042,7 +964,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;
@@ -1094,11 +1016,9 @@ 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);
-
- // 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) {
+ type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
+#if EXTSTATIC
+ if (!ft && type != 1) { // not already a feature and not found as a dynamic library
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.
@@ -1113,7 +1033,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
return 's';
}
}
-
+#endif
switch (type) {
case 0:
if (ft)
@@ -1126,13 +1046,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);
@@ -1152,18 +1072,19 @@ load_ext(VALUE path)
return (VALUE)dln_load(RSTRING_PTR(path));
}
+#if EXTSTATIC
static bool
run_static_ext_init(rb_vm_t *vm, const char *feature)
{
st_data_t key = (st_data_t)feature;
st_data_t init_func;
-
- if (vm->static_ext_inits && st_delete(vm->static_ext_inits, &key, &init_func)) {
+ if (st_delete(vm->static_ext_inits, &key, &init_func)) {
((void (*)(void))init_func)();
return true;
}
return false;
}
+#endif
static int
no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
@@ -1230,10 +1151,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;
@@ -1241,10 +1160,10 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
volatile VALUE saved_path;
volatile VALUE realpath = 0;
VALUE realpaths = get_loaded_features_realpaths(th->vm);
- VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
volatile bool reset_ext_config = false;
struct rb_ext_config prev_ext_config;
+ fname = rb_get_path(fname);
path = rb_str_encode_ospath(fname);
RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
saved_path = path;
@@ -1253,7 +1172,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
ec->errinfo = Qnil; /* ensure */
th->top_wrapper = 0;
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- VALUE handle;
+ long handle;
int found;
RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
@@ -1268,11 +1187,13 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
else if (!*ftptr) {
result = TAG_RETURN;
}
+#if EXTSTATIC
else if (found == 's' && run_static_ext_init(th->vm, RSTRING_PTR(path))) {
result = TAG_RETURN;
}
+#endif
else if (RTEST(rb_hash_aref(realpaths,
- realpath = realpath_internal_cached(realpath_map, path)))) {
+ realpath = rb_realpath_internal(Qnil, path, 1)))) {
result = 0;
}
else {
@@ -1284,9 +1205,9 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
case 's':
reset_ext_config = true;
ext_config_push(th, &prev_ext_config);
- handle = rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
- path, VM_BLOCK_HANDLER_NONE, path);
- rb_hash_aset(ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle));
+ handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
+ path, VM_BLOCK_HANDLER_NONE, path);
+ rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
break;
}
result = TAG_RETURN;
@@ -1295,7 +1216,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;
@@ -1331,8 +1251,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
rb_provide_feature(th2->vm, path);
VALUE real = realpath;
if (real) {
- real = rb_fstring(real);
- rb_hash_aset(realpaths, real, Qtrue);
+ rb_hash_aset(realpaths, rb_fstring(real), Qtrue);
}
}
ec->errinfo = saved.errinfo;
@@ -1370,12 +1289,6 @@ ruby_require_internal(const char *fname, unsigned int len)
VALUE
rb_require_string(VALUE fname)
{
- return rb_require_string_internal(FilePathValue(fname), false);
-}
-
-static VALUE
-rb_require_string_internal(VALUE fname, bool resurrect)
-{
rb_execution_context_t *ec = GET_EC();
int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
@@ -1383,7 +1296,6 @@ rb_require_string_internal(VALUE fname, bool resurrect)
EC_JUMP_TAG(ec, result);
}
if (result < 0) {
- if (resurrect) fname = rb_str_resurrect(fname);
load_failed(fname);
}
@@ -1393,11 +1305,10 @@ rb_require_string_internal(VALUE fname, bool resurrect)
VALUE
rb_require(const char *fname)
{
- struct RString fake;
- VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
- return rb_require_string_internal(str, true);
+ return rb_require_string(rb_str_new_cstr(fname));
}
+#if EXTSTATIC
static int
register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
{
@@ -1412,25 +1323,17 @@ register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing
return ST_CONTINUE;
}
-// Private API for statically linked extensions.
-// Used with the ext/Setup file, the --with-setup and
-// --with-static-linked-ext configuration option, etc.
void
ruby_init_ext(const char *name, void (*init)(void))
{
- st_table *inits_table;
rb_vm_t *vm = GET_VM();
+ st_table *inits_table = vm->static_ext_inits;
if (feature_provided(vm, name, 0))
return;
-
- inits_table = vm->static_ext_inits;
- if (!inits_table) {
- inits_table = st_init_strtable();
- vm->static_ext_inits = inits_table;
- }
st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
}
+#endif
/*
* call-seq:
@@ -1546,37 +1449,6 @@ rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
return rb_mod_autoload_p(argc, argv, klass);
}
-void *
-rb_ext_resolve_symbol(const char* fname, const char* symbol)
-{
- VALUE handle;
- VALUE resolved;
- VALUE path;
- char *ext;
- VALUE fname_str = rb_str_new_cstr(fname);
-
- resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
- if (NIL_P(resolved)) {
- ext = strrchr(fname, '.');
- if (!ext || !IS_SOEXT(ext)) {
- rb_str_cat_cstr(fname_str, ".so");
- }
- if (rb_feature_p(GET_VM(), fname, 0, FALSE, FALSE, 0)) {
- return dln_symbol(NULL, symbol);
- }
- return NULL;
- }
- if (RARRAY_LEN(resolved) != 2 || rb_ary_entry(resolved, 0) != ID2SYM(rb_intern("so"))) {
- return NULL;
- }
- path = rb_ary_entry(resolved, 1);
- handle = rb_hash_lookup(ruby_dln_libmap, path);
- if (NIL_P(handle)) {
- return NULL;
- }
- return dln_symbol((void *)NUM2SVALUE(handle), symbol);
-}
-
void
Init_load(void)
{
@@ -1600,8 +1472,6 @@ Init_load(void)
vm->loaded_features_index = st_init_numtable();
vm->loaded_features_realpaths = rb_hash_new();
rb_obj_hide(vm->loaded_features_realpaths);
- vm->loaded_features_realpath_map = rb_hash_new();
- rb_obj_hide(vm->loaded_features_realpath_map);
rb_define_global_function("load", rb_f_load, -1);
rb_define_global_function("require", rb_f_require, 1);
@@ -1611,6 +1481,6 @@ Init_load(void)
rb_define_global_function("autoload", rb_f_autoload, 2);
rb_define_global_function("autoload?", rb_f_autoload_p, -1);
- ruby_dln_libmap = rb_hash_new_with_size(0);
- rb_gc_register_mark_object(ruby_dln_libmap);
+ ruby_dln_librefs = rb_ary_hidden_new(0);
+ rb_gc_register_mark_object(ruby_dln_librefs);
}
diff --git a/main.c b/main.c
index 97c2858eea..0d0ec147cd 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,16 +43,10 @@ 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 6cb636f3ff..7152be2924 100644
--- a/marshal.c
+++ b/marshal.c
@@ -173,8 +173,7 @@ struct dump_arg {
st_table *data;
st_table *compat_tbl;
st_table *encodings;
- st_table *userdefs;
- st_index_t num_entries;
+ unsigned long num_entries;
};
struct dump_call_arg {
@@ -222,7 +221,6 @@ mark_dump_arg(void *ptr)
rb_mark_set(p->symbols);
rb_mark_set(p->data);
rb_mark_hash(p->compat_tbl);
- rb_mark_set(p->userdefs);
rb_gc_mark(p->str);
}
@@ -230,25 +228,19 @@ static void
free_dump_arg(void *ptr)
{
clear_dump_arg(ptr);
+ xfree(ptr);
}
static size_t
memsize_dump_arg(const void *ptr)
{
- const struct dump_arg *p = (struct dump_arg *)ptr;
- size_t memsize = 0;
- if (p->symbols) memsize += rb_st_memsize(p->symbols);
- if (p->data) memsize += rb_st_memsize(p->data);
- if (p->compat_tbl) memsize += rb_st_memsize(p->compat_tbl);
- if (p->userdefs) memsize += rb_st_memsize(p->userdefs);
- if (p->encodings) memsize += rb_st_memsize(p->encodings);
- return memsize;
+ return sizeof(struct dump_arg);
}
static const rb_data_type_t dump_arg_data = {
"dump_arg",
{mark_dump_arg, free_dump_arg, memsize_dump_arg,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
@@ -469,7 +461,7 @@ w_float(double d, struct dump_arg *arg)
memcpy(buf + len, p, digs);
len += digs;
}
- free(p);
+ xfree(p);
w_bytes(buf, len, arg);
}
}
@@ -531,7 +523,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)
@@ -613,8 +605,10 @@ struct w_ivar_arg {
};
static int
-w_obj_each(ID id, VALUE value, st_data_t a)
+w_obj_each(st_data_t key, st_data_t val, st_data_t a)
{
+ ID id = (ID)key;
+ VALUE value = (VALUE)val;
struct w_ivar_arg *ivarg = (struct w_ivar_arg *)a;
struct dump_call_arg *arg = ivarg->dump;
@@ -636,8 +630,9 @@ w_obj_each(ID id, VALUE value, st_data_t a)
}
static int
-obj_count_ivars(ID id, VALUE val, st_data_t a)
+obj_count_ivars(st_data_t key, st_data_t val, st_data_t a)
{
+ ID id = (ID)key;
if (!to_be_skipped_id(id) && UNLIKELY(!++*(st_index_t *)a)) {
rb_raise(rb_eRuntimeError, "too many instance variables");
}
@@ -907,9 +902,6 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
st_index_t hasiv2;
VALUE encname2;
- if (arg->userdefs && st_is_member(arg->userdefs, (st_data_t)obj)) {
- rb_raise(rb_eRuntimeError, "can't dump recursive object using _dump()");
- }
v = INT2NUM(limit);
v = dump_funcall(arg, obj, s_dump, 1, &v);
if (!RB_TYPE_P(v, T_STRING)) {
@@ -926,13 +918,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
w_class(TYPE_USERDEF, obj, arg, FALSE);
w_bytes(RSTRING_PTR(v), RSTRING_LEN(v), arg);
if (hasiv) {
- st_data_t userdefs = (st_data_t)obj;
- if (!arg->userdefs) {
- arg->userdefs = rb_init_identtable();
- }
- st_add_direct(arg->userdefs, userdefs, 0);
w_ivar(hasiv, ivobj, encname, &c_arg);
- st_delete(arg->userdefs, &userdefs, NULL);
}
w_remember(obj, arg);
return;
@@ -1139,10 +1125,6 @@ clear_dump_arg(struct dump_arg *arg)
st_free_table(arg->encodings);
arg->encodings = 0;
}
- if (arg->userdefs) {
- st_free_table(arg->userdefs);
- arg->userdefs = 0;
- }
}
NORETURN(static inline void io_needed(void));
@@ -1220,7 +1202,6 @@ rb_marshal_dump_limited(VALUE obj, VALUE port, int limit)
arg->num_entries = 0;
arg->compat_tbl = 0;
arg->encodings = 0;
- arg->userdefs = 0;
arg->str = rb_str_buf_new(0);
if (!NIL_P(port)) {
if (!rb_respond_to(port, s_write)) {
@@ -1291,24 +1272,19 @@ static void
free_load_arg(void *ptr)
{
clear_load_arg(ptr);
+ xfree(ptr);
}
static size_t
memsize_load_arg(const void *ptr)
{
- const struct load_arg *p = (struct load_arg *)ptr;
- size_t memsize = 0;
- if (p->symbols) memsize += rb_st_memsize(p->symbols);
- if (p->data) memsize += rb_st_memsize(p->data);
- if (p->partial_objects) memsize += rb_st_memsize(p->partial_objects);
- if (p->compat_tbl) memsize += rb_st_memsize(p->compat_tbl);
- return memsize;
+ return sizeof(struct load_arg);
}
static const rb_data_type_t load_arg_data = {
"load_arg",
{mark_load_arg, free_load_arg, memsize_load_arg,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
#define r_entry(v, arg) r_entry0((v), (arg)->data->num_entries, (arg))
@@ -1697,9 +1673,10 @@ r_leave(VALUE v, struct load_arg *arg, bool partial)
}
static int
-copy_ivar_i(ID vid, VALUE value, st_data_t arg)
+copy_ivar_i(st_data_t key, st_data_t val, st_data_t arg)
{
- VALUE obj = (VALUE)arg;
+ VALUE obj = (VALUE)arg, value = (VALUE)val;
+ ID vid = (ID)key;
if (!rb_ivar_defined(obj, vid))
rb_ivar_set(obj, vid, value);
@@ -1849,6 +1826,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
case TYPE_IVAR:
{
int ivar = TRUE;
+
v = r_object0(arg, true, &ivar, extmod);
if (ivar) r_ivar(v, NULL, arg);
v = r_leave(v, arg, partial);
@@ -1887,7 +1865,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;
@@ -2042,10 +2019,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);
-
- v = r_entry0(regexp, idx, arg);
+ v = r_entry0(rb_reg_new_str(str, options), idx, arg);
v = r_leave(v, arg, partial);
}
break;
@@ -2164,12 +2138,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;
@@ -2194,9 +2163,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);
@@ -2534,20 +2500,6 @@ Init_marshal(void)
rb_define_const(rb_mMarshal, "MINOR_VERSION", INT2FIX(MARSHAL_MINOR));
}
-static int
-free_compat_i(st_data_t key, st_data_t value, st_data_t _)
-{
- xfree((marshal_compat_t *)value);
- return ST_CONTINUE;
-}
-
-static void
-free_compat_allocator_table(void *data)
-{
- st_foreach(data, free_compat_i, 0);
- st_free_table(data);
-}
-
static st_table *
compat_allocator_table(void)
{
@@ -2556,7 +2508,7 @@ compat_allocator_table(void)
#undef RUBY_UNTYPED_DATA_WARNING
#define RUBY_UNTYPED_DATA_WARNING 0
compat_allocator_tbl_wrapper =
- Data_Wrap_Struct(0, mark_marshal_compat_t, free_compat_allocator_table, compat_allocator_tbl);
+ Data_Wrap_Struct(0, mark_marshal_compat_t, 0, compat_allocator_tbl);
rb_gc_register_mark_object(compat_allocator_tbl_wrapper);
return compat_allocator_tbl;
}
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 ad66690c6a..d33ab5053c 100644
--- a/method.h
+++ b/method.h
@@ -101,9 +101,8 @@ static inline void
METHOD_ENTRY_FLAGS_COPY(rb_method_entry_t *dst, const rb_method_entry_t *src)
{
dst->flags =
- (dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2
- |IMEMO_FL_USER3)) |
- (src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3));
+ (dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2)) |
+ (src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2));
}
typedef enum {
@@ -153,6 +152,7 @@ typedef struct rb_method_alias_struct {
typedef struct rb_method_refined_struct {
struct rb_method_entry_struct * orig_me;
+ VALUE owner;
} rb_method_refined_t;
typedef struct rb_method_bmethod_struct {
@@ -178,9 +178,9 @@ typedef struct rb_method_optimized {
struct rb_method_definition_struct {
BITFIELD(rb_method_type_t, type, VM_METHOD_TYPE_MINIMUM_BITS);
unsigned int iseq_overload: 1;
+ int alias_count : 27;
+ int complemented_count : 28;
unsigned int no_redef_warning: 1;
- unsigned int aliased : 1;
- int reference_count : 28;
union {
rb_method_iseq_t iseq;
@@ -199,7 +199,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) \
@@ -213,7 +213,7 @@ void rb_add_method_optimized(VALUE klass, ID mid, enum method_optimized_type, un
void rb_add_refined_method_entry(VALUE refined_class, ID mid);
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_visibility_t noex);
-rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, rb_method_definition_t *def);
+rb_method_entry_t *rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, const rb_method_definition_t *def);
const rb_method_entry_t *rb_method_entry_at(VALUE obj, ID id);
@@ -249,6 +249,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 457327ee06..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; */
};
@@ -78,7 +74,6 @@ each_builtin_i(st_data_t key, st_data_t val, st_data_t dmy)
return ST_CONTINUE;
}
-/* :nodoc: */
static VALUE
each_builtin(VALUE self)
{
diff --git a/miniinit.c b/miniinit.c
index bb22d6d9f5..2a14a0d1c5 100644
--- a/miniinit.c
+++ b/miniinit.c
@@ -49,10 +49,3 @@ Init_enc(void)
}
#include "mini_builtin.c"
-
-void
-rb_free_loaded_builtin_table(void)
-{
- if (loaded_builtin_table)
- st_free_table(loaded_builtin_table);
-}
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/call_fuzzer.rb b/misc/call_fuzzer.rb
deleted file mode 100644
index c3f9f90490..0000000000
--- a/misc/call_fuzzer.rb
+++ /dev/null
@@ -1,372 +0,0 @@
-require 'optparse'
-require 'set'
-
-# Number of iterations to test
-num_iters = 10_000
-
-# Parse the command-line options
-OptionParser.new do |opts|
- opts.on("--num-iters=N") do |n|
- num_iters = n.to_i
- end
-end.parse!
-
-# Format large numbers with comma separators for readability
-def format_number(pad, number)
- s = number.to_s
- i = s.index('.') || s.size
- s.insert(i -= 3, ',') while i > 3
- s.rjust(pad, ' ')
-end
-
-# Wrap an integer to pass as argument
-# We use this so we can have some object arguments
-class IntWrapper
- def initialize(v)
- # Force the object to have a random shape
- if rand() < 50
- @v0 = 1
- end
- if rand() < 50
- @v1 = 1
- end
- if rand() < 50
- @v2 = 1
- end
- if rand() < 50
- @v3 = 1
- end
- if rand() < 50
- @v4 = 1
- end
- if rand() < 50
- @v5 = 1
- end
- if rand() < 50
- @v6 = 1
- end
-
- @value = v
- end
-
- attr_reader :value
-end
-
-# Generate a random argument value, integer or string or object
-def sample_arg()
- c = ['int', 'string', 'object'].sample()
-
- if c == 'int'
- return rand(0...100)
- end
-
- if c == 'string'
- return 'f' * rand(0...100)
- end
-
- if c == 'object'
- return IntWrapper.new(rand(0...100))
- end
-
- raise "should not get here"
-end
-
-# Evaluate the value of an argument with respect to the checksum
-def arg_val(arg)
- if arg.kind_of? Integer
- return arg
- end
-
- if arg.kind_of? String
- return arg.length
- end
-
- if arg.kind_of? Object
- return arg.value
- end
-
- raise "unknown arg type"
-end
-
-# List of parameters/arguments for a method
-class ParamList
- def initialize()
- self.sample_params()
- self.sample_args()
- end
-
- # Sample/generate a random set of parameters for a method
- def sample_params()
- # Choose how many positional arguments to use, and how many are optional
- num_pargs = rand(10)
- @opt_parg_idx = rand(num_pargs)
- @num_opt_pargs = rand(num_pargs + 1 - @opt_parg_idx)
- @num_pargs_req = num_pargs - @num_opt_pargs
- @pargs = (0...num_pargs).map do |i|
- {
- :name => "p#{i}",
- :optional => (i >= @opt_parg_idx && i < @opt_parg_idx + @num_opt_pargs)
- }
- end
-
- # Choose how many kwargs to use, and how many are optional
- num_kwargs = rand(10)
- @kwargs = (0...num_kwargs).map do |i|
- {
- :name => "k#{i}",
- :optional => rand() < 0.5
- }
- end
-
- # Choose whether to have rest parameters or not
- @has_rest = @num_opt_pargs == 0 && rand() < 0.5
- @has_kwrest = rand() < 0.25
-
- # Choose whether to have a named block parameter or not
- @has_block_param = rand() < 0.25
- end
-
- # Sample/generate a random set of arguments corresponding to the parameters
- def sample_args()
- # Choose how many positional args to pass
- num_pargs_passed = rand(@num_pargs_req..@pargs.size)
-
- # How many optional arguments will be filled
- opt_pargs_filled = num_pargs_passed - @num_pargs_req
-
- @pargs.each_with_index do |parg, i|
- if parg[:optional]
- parg[:default] = rand(100)
- end
-
- if !parg[:optional] || i < @opt_parg_idx + opt_pargs_filled
- parg[:argval] = rand(100)
- end
- end
-
- @kwargs.each_with_index do |kwarg, i|
- if kwarg[:optional]
- kwarg[:default] = rand(100)
- end
-
- if !kwarg[:optional] || rand() < 0.5
- kwarg[:argval] = rand(100)
- end
- end
-
- # Randomly pass a block or not
- @block_arg = nil
- if rand() < 0.5
- @block_arg = rand(100)
- end
- end
-
- # Compute the expected checksum of arguments ahead of time
- def compute_checksum()
- checksum = 0
-
- @pargs.each_with_index do |arg, i|
- value = (arg.key? :argval)? arg[:argval]:arg[:default]
- checksum += (i+1) * arg_val(value)
- end
-
- @kwargs.each_with_index do |arg, i|
- value = (arg.key? :argval)? arg[:argval]:arg[:default]
- checksum += (i+1) * arg_val(value)
- end
-
- if @block_arg
- if @has_block_param
- checksum += arg_val(@block_arg)
- end
-
- checksum += arg_val(@block_arg)
- end
-
- checksum
- end
-
- # Generate code for the method signature and method body
- def gen_method_str()
- m_str = "def m("
-
- @pargs.each do |arg|
- if !m_str.end_with?("(")
- m_str += ", "
- end
-
- m_str += arg[:name]
-
- # If this has a default value
- if arg[:optional]
- m_str += " = #{arg[:default]}"
- end
- end
-
- if @has_rest
- if !m_str.end_with?("(")
- m_str += ", "
- end
- m_str += "*rest"
- end
-
- @kwargs.each do |arg|
- if !m_str.end_with?("(")
- m_str += ", "
- end
-
- m_str += "#{arg[:name]}:"
-
- # If this has a default value
- if arg[:optional]
- m_str += " #{arg[:default]}"
- end
- end
-
- if @has_kwrest
- if !m_str.end_with?("(")
- m_str += ", "
- end
- m_str += "**kwrest"
- end
-
- if @has_block_param
- if !m_str.end_with?("(")
- m_str += ", "
- end
-
- m_str += "&block"
- end
-
- m_str += ")\n"
-
- # Add some useless locals
- rand(0...16).times do |i|
- m_str += "local#{i} = #{i}\n"
- end
-
- # Add some useless if statements
- @pargs.each_with_index do |arg, i|
- if rand() < 50
- m_str += "if #{arg[:name]} > 4; end\n"
- end
- end
-
- m_str += "checksum = 0\n"
-
- @pargs.each_with_index do |arg, i|
- m_str += "checksum += #{i+1} * arg_val(#{arg[:name]})\n"
- end
-
- @kwargs.each_with_index do |arg, i|
- m_str += "checksum += #{i+1} * arg_val(#{arg[:name]})\n"
- end
-
- if @has_block_param
- m_str += "if block; r = block.call; checksum += arg_val(r); end\n"
- end
-
- m_str += "if block_given?; r = yield; checksum += arg_val(r); end\n"
-
- if @has_rest
- m_str += "raise 'rest is not array' unless rest.kind_of?(Array)\n"
- m_str += "raise 'rest size not integer' unless rest.size.kind_of?(Integer)\n"
- end
-
- if @has_kwrest
- m_str += "raise 'kwrest is not a hash' unless kwrest.kind_of?(Hash)\n"
- m_str += "raise 'kwrest size not integer' unless kwrest.size.kind_of?(Integer)\n"
- end
-
- m_str += "checksum\n"
- m_str += "end"
-
- m_str
- end
-
- # Generate code to call into the method and pass the arguments
- def gen_call_str()
- c_str = "m("
-
- @pargs.each_with_index do |arg, i|
- if !arg.key? :argval
- next
- end
-
- if !c_str.end_with?("(")
- c_str += ", "
- end
-
- c_str += "#{arg[:argval]}"
- end
-
- @kwargs.each_with_index do |arg, i|
- if !arg.key? :argval
- next
- end
-
- if !c_str.end_with?("(")
- c_str += ", "
- end
-
- c_str += "#{arg[:name]}: #{arg[:argval]}"
- end
-
- c_str += ")"
-
- # Randomly pass a block or not
- if @block_arg
- c_str += " { #{@block_arg} }"
- end
-
- c_str
- end
-end
-
-iseqs_compiled_start = RubyVM::YJIT.runtime_stats[:compiled_iseq_entry]
-start_time = Time.now.to_f
-
-num_iters.times do |i|
- puts "Iteration #{i}"
-
- lst = ParamList.new()
- m_str = lst.gen_method_str()
- c_str = lst.gen_call_str()
- checksum = lst.compute_checksum()
-
- f = Object.new
-
- # Define the method on f
- puts "Defining"
- p m_str
- f.instance_eval(m_str)
- #puts RubyVM::InstructionSequence.disasm(f.method(:m))
- #exit 0
-
- puts "Calling"
- c_str = "f.#{c_str}"
- p c_str
- r = eval(c_str)
- puts "checksum=#{r}"
-
- if r != checksum
- raise "return value #{r} doesn't match checksum #{checksum}"
- end
-
- puts ""
-end
-
-# Make sure that YJIT actually compiled the tests we ran
-# Should be run with --yjit-call-threshold=1
-iseqs_compiled_end = RubyVM::YJIT.runtime_stats[:compiled_iseq_entry]
-if iseqs_compiled_end - iseqs_compiled_start < num_iters
- raise "YJIT did not compile enough ISEQs"
-end
-
-puts "Code region size: #{ format_number(0, RubyVM::YJIT.runtime_stats[:code_region_size]) }"
-
-end_time = Time.now.to_f
-itrs_per_sec = num_iters / (end_time - start_time)
-itrs_per_hour = 3600 * itrs_per_sec
-puts "#{'%.1f' % itrs_per_sec} iterations/s"
-puts "#{format_number(0, itrs_per_hour.round)} iterations/hour"
diff --git a/misc/call_fuzzer.sh b/misc/call_fuzzer.sh
deleted file mode 100755
index cf4ec76fe8..0000000000
--- a/misc/call_fuzzer.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-# Stop at first error
-set -e
-
-# TODO
-# TODO: boost --num-iters to 1M+ for actual test
-# TODO
-export NUM_ITERS=25000
-
-# Enable code GC so we don't stop compiling when we hit the code size limit
-ruby --yjit-call-threshold=1 --yjit-code-gc misc/call_fuzzer.rb --num-iters=$NUM_ITERS
-
-# Do another pass with --verify-ctx
-ruby --yjit-call-threshold=1 --yjit-code-gc --yjit-verify-ctx misc/call_fuzzer.rb --num-iters=$NUM_ITERS
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 e18e468ca5..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_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/missing/setproctitle.c b/missing/setproctitle.c
index 6a85323818..811829c060 100644
--- a/missing/setproctitle.c
+++ b/missing/setproctitle.c
@@ -135,7 +135,6 @@ compat_init_setproctitle(int argc, char *argv[])
}
#ifndef HAVE_SETPROCTITLE
-
void
setproctitle(const char *fmt, ...)
{
diff --git a/mjit.c b/mjit.c
new file mode 100644
index 0000000000..282f5965f9
--- /dev/null
+++ b/mjit.c
@@ -0,0 +1,1988 @@
+/**********************************************************************
+
+ 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;
+
+// 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__
+ "-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;
+ 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);
+ }
+ }
+
+ 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;
+
+ if (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..905de6139a
--- /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],
+ alias_count: [CType::BitField.new(27, 5), 5],
+ complemented_count: [CType::BitField.new(28, 0), 32],
+ no_redef_warning: [CType::BitField.new(1, 4), 60],
+ 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 41891acf1a..b191b25d79 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;
@@ -1078,7 +1073,7 @@ flo_to_s(VALUE flt)
s = sign ? rb_usascii_str_new_cstr("-") : rb_usascii_str_new(0, 0);
if ((digs = (int)(e - p)) >= (int)sizeof(buf)) digs = (int)sizeof(buf) - 1;
memcpy(buf, p, digs);
- free(p);
+ xfree(p);
if (decpt > 0) {
if (decpt < digs) {
memmove(buf + decpt + 1, buf + decpt, digs - decpt);
@@ -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,7 +2372,11 @@ rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode)
static VALUE
rb_int_floor(VALUE num, int ndigits)
{
- VALUE f = int_pow(10, -ndigits);
+ VALUE f;
+
+ if (int_round_zero_p(num, ndigits))
+ return INT2FIX(0);
+ f = int_pow(10, -ndigits);
if (FIXNUM_P(num) && FIXNUM_P(f)) {
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
int neg = x < 0;
@@ -2382,19 +2385,21 @@ rb_int_floor(VALUE num, int ndigits)
if (neg) x = -x;
return LONG2NUM(x);
}
- 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;
+ if (RB_FLOAT_TYPE_P(f)) {
+ /* then int_pow overflow */
+ return INT2FIX(0);
}
+ return rb_int_minus(num, rb_int_modulo(num, f));
}
static VALUE
rb_int_ceil(VALUE num, int ndigits)
{
- VALUE f = int_pow(10, -ndigits);
+ VALUE f;
+
+ if (int_round_zero_p(num, ndigits))
+ return INT2FIX(0);
+ f = int_pow(10, -ndigits);
if (FIXNUM_P(num) && FIXNUM_P(f)) {
SIGNED_VALUE x = FIX2LONG(num), y = FIX2LONG(f);
int neg = x < 0;
@@ -2404,16 +2409,11 @@ rb_int_ceil(VALUE num, int ndigits)
if (neg) x = -x;
return LONG2NUM(x);
}
- 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;
+ if (RB_FLOAT_TYPE_P(f)) {
+ /* then int_pow overflow */
+ return INT2FIX(0);
}
+ return rb_int_plus(num, rb_int_minus(f, rb_int_modulo(num, f)));
}
VALUE
@@ -2591,6 +2591,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
@@ -2833,7 +2834,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;
@@ -2959,11 +2960,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.
@@ -3005,7 +3006,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 = []
@@ -3055,7 +3056,7 @@ num_step(int argc, VALUE *argv, VALUE from)
num_step_size, from, to, step, FALSE);
}
- return SIZED_ENUMERATOR_KW(from, 2, ((VALUE [2]){to, step}), num_step_size, FALSE);
+ return SIZED_ENUMERATOR(from, 2, ((VALUE [2]){to, step}), num_step_size);
}
desc = num_step_scan_args(argc, argv, &to, &step, TRUE, FALSE);
@@ -3164,7 +3165,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)) {
@@ -3439,7 +3440,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 */
@@ -3458,10 +3459,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 */
@@ -3689,6 +3695,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).
*/
@@ -3885,7 +3893,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);
@@ -3911,9 +3919,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;
@@ -4095,13 +4106,7 @@ static double
fix_fdiv_double(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
- long iy = FIX2LONG(y);
-#if SIZEOF_LONG * CHAR_BIT > DBL_MANT_DIG
- if ((iy < 0 ? -iy : iy) >= (1L << DBL_MANT_DIG)) {
- return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), rb_int2big(iy));
- }
-#endif
- return double_div_double(FIX2LONG(x), iy);
+ return double_div_double(FIX2LONG(x), FIX2LONG(y));
}
else if (RB_BIGNUM_TYPE_P(y)) {
return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), y);
@@ -4119,7 +4124,7 @@ rb_int_fdiv_double(VALUE x, VALUE y)
{
if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y)) {
VALUE gcd = rb_gcd(x, y);
- if (!FIXNUM_ZERO_P(gcd) && gcd != INT2FIX(1)) {
+ if (!FIXNUM_ZERO_P(gcd)) {
x = rb_int_idiv(x, gcd);
y = rb_int_idiv(y, gcd);
}
@@ -4310,6 +4315,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)
@@ -4350,22 +4357,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
@@ -4628,6 +4625,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
@@ -5174,7 +5174,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);
@@ -5344,7 +5344,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
@@ -5398,7 +5398,7 @@ fix_size(VALUE fix)
return INT2FIX(sizeof(long));
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_int_size(VALUE num)
{
if (FIXNUM_P(num)) {
@@ -5657,6 +5657,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
@@ -5844,11 +5896,7 @@ prefix##_isqrt(argtype n) \
while ((t = n/x) < (argtype)x) x = (rettype)((x + t) >> 1); \
return x; \
} \
- rettype x = (rettype)sqrt(argtype##_TO_DOUBLE(n)); \
- /* libm sqrt may returns a larger approximation than actual. */ \
- /* Our isqrt always returns a smaller approximation. */ \
- if (x * x > n) x--; \
- return x; \
+ return (rettype)sqrt(argtype##_TO_DOUBLE(n)); \
}
#if SIZEOF_LONG*CHAR_BIT > DBL_MANT_DIG
@@ -5941,22 +5989,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)
{
@@ -5989,9 +6022,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.
*
@@ -6005,9 +6038,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).
*
@@ -6200,6 +6233,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 5d6b6dbad1..cd50960aba 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
* \{
@@ -92,12 +80,6 @@ static VALUE rb_cFalseClass_to_s;
/*! \endcond */
-size_t
-rb_obj_embedded_size(uint32_t numiv)
-{
- return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * numiv);
-}
-
VALUE
rb_obj_hide(VALUE obj)
{
@@ -119,25 +101,18 @@ rb_obj_reveal(VALUE obj, VALUE klass)
VALUE
rb_obj_setup(VALUE obj, VALUE klass, VALUE type)
{
- VALUE ignored_flags = RUBY_FL_PROMOTED | RUBY_FL_SEEN_OBJ_ID;
- RBASIC(obj)->flags = (type & ~ignored_flags) | (RBASIC(obj)->flags & ignored_flags);
+ RBASIC(obj)->flags = type;
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
@@ -210,7 +185,7 @@ rb_eql(VALUE obj1, VALUE obj2)
* \private
*++
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
return RBOOL(obj1 == obj2);
@@ -228,7 +203,7 @@ VALUE rb_obj_hash(VALUE obj);
*++
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_obj_not(VALUE obj)
{
return RBOOL(!RTEST(obj));
@@ -244,7 +219,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);
@@ -291,7 +266,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));
@@ -299,10 +274,13 @@ 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)) {
- // obj is TOO_COMPLEX so we can copy its iv_hash
- st_table *table = st_copy(ROBJECT_IV_HASH(obj));
- rb_obj_convert_to_too_complex(dest, table);
+ if (rb_shape_id(src_shape) == OBJ_TOO_COMPLEX_SHAPE_ID) {
+ struct rb_id_table * table = rb_id_table_create(rb_id_table_size(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);
+
+ ROBJECT(dest)->as.heap.ivptr = (VALUE *)table;
return;
}
@@ -330,16 +308,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_obj_copy_ivs_to_hash_table(obj, table);
- rb_obj_convert_to_too_complex(dest, 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);
@@ -453,12 +424,15 @@ immutable_obj_clone(VALUE obj, VALUE kwfreeze)
return obj;
}
-VALUE
-rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
+static VALUE
+mutable_obj_clone(VALUE obj, VALUE kwfreeze)
{
+ VALUE clone, singleton;
VALUE argv[2];
- VALUE singleton = rb_singleton_class_clone_and_attach(obj, clone);
+ clone = rb_obj_alloc(rb_obj_class(obj));
+
+ singleton = rb_singleton_class_clone_and_attach(obj, clone);
RBASIC_SET_CLASS(clone, singleton);
if (FL_TEST(singleton, FL_SINGLETON)) {
rb_singleton_class_attached(singleton, clone);
@@ -471,16 +445,11 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, 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);
- }
- 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();
@@ -493,18 +462,11 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, 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);
- }
- 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();
@@ -517,7 +479,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, 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");
}
@@ -525,13 +487,6 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
return clone;
}
-static VALUE
-mutable_obj_clone(VALUE obj, VALUE kwfreeze)
-{
- VALUE clone = rb_obj_alloc(rb_obj_class(obj));
- return rb_obj_clone_setup(obj, clone, kwfreeze);
-}
-
VALUE
rb_obj_clone(VALUE obj)
{
@@ -539,15 +494,6 @@ rb_obj_clone(VALUE obj)
return mutable_obj_clone(obj, Qnil);
}
-VALUE
-rb_obj_dup_setup(VALUE obj, VALUE dup)
-{
- init_copy(dup, obj);
- rb_funcall(dup, id_init_dup, 1, obj);
-
- return dup;
-}
-
/*
* call-seq:
* obj.dup -> an_object
@@ -596,7 +542,10 @@ rb_obj_dup(VALUE obj)
return obj;
}
dup = rb_obj_alloc(rb_obj_class(obj));
- return rb_obj_dup_setup(obj, dup);
+ init_copy(dup, obj);
+ rb_funcall(dup, id_init_dup, 1, obj);
+
+ return dup;
}
/*
@@ -622,6 +571,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:
*--
@@ -718,8 +673,10 @@ rb_inspect(VALUE obj)
}
static int
-inspect_i(ID id, VALUE value, st_data_t a)
+inspect_i(st_data_t k, st_data_t v, st_data_t a)
{
+ ID id = (ID)k;
+ VALUE value = (VALUE)v;
VALUE str = (VALUE)a;
/* need not to show internal data */
@@ -1302,47 +1259,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;
@@ -1351,13 +1278,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
@@ -1369,13 +1295,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
@@ -1385,13 +1310,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
@@ -1401,17 +1323,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
@@ -1420,38 +1337,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;
@@ -1460,14 +1363,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
@@ -1478,21 +1377,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
@@ -1504,14 +1400,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
@@ -1538,27 +1431,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)
{
@@ -1567,30 +1455,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>.
*
*/
@@ -1598,10 +1480,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
@@ -1621,7 +1502,7 @@ rb_true(VALUE obj)
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_false(VALUE obj)
{
return Qfalse;
@@ -1706,7 +1587,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;
@@ -1714,7 +1595,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));
@@ -2198,10 +2079,6 @@ rb_class_superclass(VALUE klass)
if (klass == rb_cBasicObject) return Qnil;
rb_raise(rb_eTypeError, "uninitialized class");
}
-
- if (!RCLASS_SUPERCLASS_DEPTH(klass)) {
- return Qnil;
- }
else {
super = RCLASS_SUPERCLASSES(klass)[RCLASS_SUPERCLASS_DEPTH(klass) - 1];
RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS));
@@ -3180,7 +3057,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;
@@ -3345,17 +3222,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
@@ -3489,7 +3470,6 @@ 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) {
@@ -3949,6 +3929,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
@@ -4174,7 +4157,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.
@@ -4190,6 +4173,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)
{
@@ -4405,6 +4409,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);
@@ -4440,7 +4446,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 f84320b4b4..bd3251e4e1 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,32 +388,20 @@ 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 inline bool
-end_with_newline_p(struct parser_params *p, VALUE str)
+static st_table *
+push_pvtbl(struct parser_params *p)
{
- return RSTRING_LEN(str) > 0 && RSTRING_END(str)[-1] == '\n';
+ st_table *tbl = p->pvtbl;
+ p->pvtbl = st_init_numtable();
+ return tbl;
}
static void
@@ -575,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)
{
@@ -619,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);
@@ -651,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);
@@ -800,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);
@@ -820,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)
@@ -839,282 +681,18 @@ 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 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);
-static rb_node_def_temp_t *def_head_save(struct parser_params *p, rb_node_def_temp_t *n);
-
-#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
- * 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_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 NODE *nd_set_loc(NODE *nd, const YYLTYPE *loc);
@@ -1126,14 +704,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)
@@ -1142,32 +712,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)
-{
- while (expr) {
- if (nd_type_p(expr, NODE_BLOCK)) {
- expr = RNODE_BLOCK(RNODE_BLOCK(expr)->nd_end)->nd_head;
- }
- else if (nd_type_p(expr, NODE_BEGIN)) {
- expr = RNODE_BEGIN(expr)->nd_body;
- }
- else {
- break;
- }
+ nd_set_line(body, line);
}
- return expr;
}
#define yyparse ruby_yyparse
@@ -1186,6 +732,7 @@ static void fixpos(NODE*,NODE*);
static int value_expr_gen(struct parser_params*,NODE*);
static void void_expr(struct parser_params*,NODE*);
static NODE *remove_begin(NODE*);
+static NODE *remove_begin_all(NODE*);
#define value_expr(node) value_expr_gen(p, (node))
static NODE *void_stmts(struct parser_params*,NODE*);
static void reduce_nodes(struct parser_params*,NODE**);
@@ -1200,7 +747,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);
@@ -1209,24 +755,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*);
@@ -1247,8 +793,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);
@@ -1270,6 +816,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*);
@@ -1280,29 +827,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);
}
@@ -1310,11 +850,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);
@@ -1340,11 +880,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);
@@ -1377,7 +920,6 @@ static NODE *new_args_forward_call(struct parser_params*, NODE*, const YYLTYPE*,
#endif
static int check_forwarding_args(struct parser_params*);
static void add_forwarding_args(struct parser_params *p);
-static void forwarding_arg_check(struct parser_params *p, ID arg, ID all, const char *var);
static const struct vtable *dyna_push(struct parser_params *);
static void dyna_pop(struct parser_params*, const struct vtable *);
@@ -1402,11 +944,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)
@@ -1417,6 +954,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);
@@ -1432,11 +1035,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);
@@ -1445,7 +1049,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))
@@ -1464,18 +1068,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
@@ -1487,16 +1097,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);
}
@@ -1504,14 +1114,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);
}
@@ -1519,7 +1142,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)
@@ -1533,21 +1165,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))
@@ -1560,19 +1197,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);
@@ -1582,62 +1220,29 @@ 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)
+restore_defun(struct parser_params *p, NODE *name)
{
- next->in_rescue = outer->in_rescue == after_rescue ? after_rescue : def;
+ YYSTYPE c = {.val = name->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;
}
static void
-restore_defun(struct parser_params *p, rb_node_def_temp_t *temp)
-{
- /* 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);
-}
-
-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
@@ -1670,7 +1275,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)
@@ -1693,6 +1298,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
@@ -1708,205 +1314,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
@@ -1914,39 +1330,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
@@ -1962,15 +1375,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;
@@ -2051,56 +1455,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 arg_splat 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> args call_args opt_call_args
+%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"
@@ -2191,3400 +1578,3374 @@ 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_ERROR(&@$);
- /*% %*/
- /*% 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_ERROR(&@$);
- /*% %*/
- /*% 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, ID2VAL(idCOLON2), $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
- ;
+ | 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);
- numparam_name(p, fname);
- local_push(p, 0);
- p->cur_arg = 0;
- p->ctxt.in_def = 1;
- p->ctxt.in_rescue = before_rescue;
- $$ = $1;
- }
- ;
+ {
+ ID fname = get_id($1);
+ ID cur_arg = p->cur_arg;
+ YYSTYPE c = {.ctxt = p->ctxt};
+ numparam_name(p, fname);
+ local_push(p, 0);
+ p->cur_arg = 0;
+ p->ctxt.in_def = 1;
+ $<node>$ = NEW_NODE(NODE_SELF, /*vid*/cur_arg, /*mid*/fname, /*cval*/c.val, &@$);
+ /*%%%*/
+ /*%
+ $$ = NEW_RIPPER(fname, get_value($1), $$, &NULL_LOC);
+ %*/
+ }
+ ;
defn_head : k_def def_name
- {
- $$ = def_head_save(p, $k_def);
- $$->nd_mid = $def_name;
- /*%%%*/
- $$->nd_def = NEW_DEFN($def_name, 0, &@$);
- /*%
- add_mark_object(p, $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 */
- $$ = def_head_save(p, $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, ID2VAL(idCOLON2), $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, ID2VAL(idCOLON2), $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_ERROR(&@$);
- /*% %*/
- /*% 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_ERROR(&@$);
- /*% %*/
- /*% 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, ID2VAL(idCOLON2), $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_ERROR(&@$);
- /*% %*/
- /*% 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, ID2VAL(idCOLON2), $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
{
- forwarding_arg_check(p, idFWD_BLOCK, 0, "block");
+ if (!local_id(p, idFWD_BLOCK)) {
+ compile_error(p, "no anonymous block parameter");
+ }
/*%%%*/
$$ = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, &@1), &@$);
/*% %*/
/*% 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) %*/
- }
- | arg_splat
- {
- /*%%%*/
- $$ = NEW_SPLAT($arg_splat, &@$);
- /*% %*/
- /*% ripper: args_add_star!(args_new!, $arg_splat) %*/
- }
- | args ',' arg_value
- {
- /*%%%*/
- $$ = last_arg_append(p, $1, $3, &@$);
- /*% %*/
- /*% ripper: args_add!($1, $3) %*/
- }
- | args ',' arg_splat
- {
- /*%%%*/
- $$ = rest_arg_append(p, $1, $3, &@$);
- /*% %*/
- /*% ripper: args_add_star!($1, $3) %*/
- }
- ;
-
-/* value */
-arg_splat : tSTAR arg_value
- {
- $$ = $2;
- }
- | tSTAR /* none */
- {
- forwarding_arg_check(p, idFWD_REST, idFWD_ALL, "rest");
- /*%%%*/
- $$ = NEW_LVAR(idFWD_REST, &@1);
- /*% %*/
- /*% ripper: Qnil %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 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
+ {
+ 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) %*/
+ }
+ ;
/* 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;
- $$ = NEW_BLOCK($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_value
- {
- begin_definition("", &@k_class, &@tLSHFT);
- }
- term
- bodystmt
- k_end
- {
- /*%%%*/
- $$ = NEW_SCLASS($expr_value, $bodystmt, &@$);
- nd_set_line(RNODE_SCLASS($$)->nd_body, @k_end.end_pos.lineno);
- set_line_body($bodystmt, nd_line($expr_value));
- fixpos($$, $expr_value);
- /*% %*/
- /*% ripper: sclass!($expr_value, $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, ID2VAL(idCOLON2), $3), $4) %*/
+ }
+ | primary_value tCOLON2 operation3
+ {
+ /*%%%*/
+ $$ = new_qcall(p, ID2VAL(idCOLON2), $1, $3, Qnull, &@3, &@$);
+ /*% %*/
+ /*% ripper: call!($1, ID2VAL(idCOLON2), $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, ID2VAL(idCOLON2), 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_ERROR(&@$);
- /*% %*/
- /*% 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_BLOCK($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);
}
@@ -5594,1082 +4955,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_ERROR(&@$);
- /*% %*/
- /*% 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_ERROR(&@$);
- /*% %*/
- /*% 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_ERROR(&@$);
- $$ = 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());
@@ -6679,84 +6047,87 @@ assoc : arg_value tASSOC arg_value
}
else
$$ = list_append(p, NEW_LIST(0, &@$), $2);
- /*% %*/
- /*% ripper: assoc_splat!($2) %*/
- }
- | tDSTAR
- {
- forwarding_arg_check(p, idFWD_KWREST, idFWD_ALL, "keyword rest");
- /*%%%*/
+ /*% %*/
+ /*% 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
@@ -6815,21 +6186,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;
@@ -6844,15 +6210,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);
}
}
@@ -6866,8 +6232,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);
@@ -6877,6 +6243,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;
@@ -6884,7 +6253,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;
@@ -6892,7 +6265,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)
@@ -6922,7 +6302,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;
@@ -6938,7 +6317,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);
}
@@ -6946,7 +6325,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
@@ -6960,13 +6339,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;
@@ -7010,12 +6389,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));
@@ -7033,8 +6412,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
@@ -7042,14 +6421,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)
@@ -7057,32 +6436,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;
}
@@ -7095,7 +6474,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;
@@ -7111,13 +6490,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;
@@ -7129,72 +6508,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);
}
@@ -7204,16 +6583,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;
}
@@ -7237,10 +6616,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
@@ -7255,7 +6634,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;
@@ -7264,39 +6643,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;
}
@@ -7305,15 +6684,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;
}
@@ -7326,11 +6705,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;
}
@@ -7340,6 +6719,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)
{
@@ -7352,30 +6747,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);
@@ -7385,31 +6785,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);
@@ -7417,24 +6819,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);
@@ -7445,11 +6848,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;
}
@@ -7464,9 +6867,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;
@@ -7479,37 +6882,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)
{
@@ -7517,13 +6928,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
@@ -7533,14 +6948,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 */
@@ -7567,46 +6986,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)
@@ -7620,74 +7015,60 @@ add_delayed_token(struct parser_params *p, const char *tok, const char *end, int
#endif
if (tok < end) {
- if (has_delayed_token(p)) {
- bool next_line = end_with_newline_p(p, p->delayed.token);
- int end_line = (next_line ? 1 : 0) + p->delayed.end_line;
- int end_col = (next_line ? 0 : p->delayed.end_col);
- if (end_line != p->ruby_sourceline || end_col != tok - p->lex.pbeg) {
- dispatch_delayed_token(p, tSTRING_CONTENT);
- }
- }
- 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;
}
@@ -7695,8 +7076,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;
}
@@ -7706,12 +7087,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;
@@ -7722,10 +7103,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--;
}
}
@@ -7739,12 +7119,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;
}
@@ -7753,13 +7133,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;
}
@@ -7770,8 +7151,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];
}
@@ -7781,8 +7162,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);
}
}
@@ -7791,11 +7172,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");
- dispatch_scan_event(p, tSTRING_CONTENT);
- return 0;
+ yyerror0("invalid hex escape");
+ token_flush(p);
+ return 0;
}
p->lex.pcur += *numlen;
return c;
@@ -7809,23 +7190,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;
}
@@ -7835,14 +7216,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");
@@ -7860,41 +7241,29 @@ 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{}
@@ -7908,77 +7277,50 @@ 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) {
- /*
- * Skip parsing validation code and copy bytes as-is until term or
- * closing brace, in order to correctly handle extended regexps where
- * invalid unicode escapes are allowed in comments. The regexp parser
- * does its own validation and will catch any issues.
- */
- tokadd(p, open_brace);
- while (!lex_eol_ptr_p(p, ++p->lex.pcur)) {
- int c = peekc(p);
- if (c == close_brace) {
- tokadd(p, c);
- ++p->lex.pcur;
- break;
- }
- else if (c == term) {
- break;
- }
- if (c == '\\' && !lex_eol_n_p(p, 1)) {
- tokadd(p, c);
- c = *++p->lex.pcur;
- }
- tokadd_mbchar(p, c);
- }
- }
- 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));
- while (c != close_brace) {
- if (c == term) goto unterminated;
- if (second == multiple_codepoints)
- second = p->lex.pcur;
- if (regexp_literal) tokadd(p, last);
- 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;
- last = c;
- }
- if (term == -1 && !second)
- second = multiple_codepoints;
- }
-
- if (c != close_brace) {
- unterminated:
- token_flush(p);
- yyerror0("unterminated Unicode escape");
- return;
- }
- if (second && second != multiple_codepoints) {
- const char *pcur = p->lex.pcur;
- p->lex.pcur = second;
- dispatch_scan_event(p, tSTRING_CONTENT);
- token_flush(p);
- p->lex.pcur = pcur;
- yyerror0(multiple_codepoints);
- token_flush(p);
- }
-
- if (regexp_literal) tokadd(p, close_brace);
- nextc(p);
- }
+ const char *second = NULL;
+ int c, last = nextc(p);
+ 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)
+ second = p->lex.pcur;
+ if (regexp_literal) tokadd(p, last);
+ if (!tokadd_codepoint(p, encp, regexp_literal, TRUE)) {
+ break;
+ }
+ while (ISSPACE(c = *p->lex.pcur)) {
+ if (++p->lex.pcur >= p->lex.pend) goto unterminated;
+ last = c;
+ }
+ if (term == -1 && !second)
+ second = multiple_codepoints;
+ }
+
+ if (c != close_brace) {
+ unterminated:
+ token_flush(p);
+ yyerror0("unterminated Unicode escape");
+ return;
+ }
+ if (second && second != multiple_codepoints) {
+ const char *pcur = p->lex.pcur;
+ p->lex.pcur = second;
+ dispatch_scan_event(p, tSTRING_CONTENT);
+ token_flush(p);
+ p->lex.pcur = pcur;
+ yyerror0(multiple_codepoints);
+ token_flush(p);
+ }
+
+ if (regexp_literal) tokadd(p, close_brace);
+ nextc(p);
}
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;
+ }
}
}
@@ -7986,139 +7328,131 @@ 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)) != '-') {
- 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) goto eof;
- else if (!ISASCII(c)) {
- tokskip_mbchar(p);
- 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);
- }
+ 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 || !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);
+ }
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) goto eof;
- else if (!ISASCII(c)) {
- tokskip_mbchar(p);
- 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;
- }
- return c & 0x9f;
+ 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 || !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;
+ }
+ return c & 0x9f;
eof:
case -1:
yyerror0("Invalid escape character syntax");
- dispatch_scan_event(p, tSTRING_CONTENT);
- return '\0';
+ token_flush(p);
+ return '\0';
default:
- return c;
+ return c;
}
}
@@ -8130,42 +7464,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;
}
@@ -8184,26 +7518,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);
}
@@ -8226,9 +7560,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;
}
}
@@ -8236,24 +7570,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;
}
@@ -8276,17 +7610,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;
@@ -8301,9 +7628,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);
@@ -8311,131 +7638,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) {
+ int 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:
@@ -8443,27 +7771,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
@@ -8471,32 +7807,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),
@@ -8511,33 +7847,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;
}
@@ -8546,26 +7882,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;
@@ -8574,76 +7909,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 == '#') {
- enum yytokentype 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);
@@ -8667,71 +8000,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;
@@ -8743,7 +8075,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;
@@ -8756,12 +8087,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;
@@ -8769,23 +8098,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;
@@ -8804,42 +8133,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;
}
@@ -8854,31 +8183,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) {
@@ -8898,36 +8247,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);
@@ -8939,8 +8288,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);
}
@@ -8951,7 +8300,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);
@@ -8965,12 +8314,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);
@@ -8997,148 +8346,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 == '#') {
- enum yytokentype 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;
}
@@ -9172,27 +8523,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);
@@ -9212,16 +8563,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;
}
@@ -9234,26 +8585,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
}
@@ -9264,8 +8615,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;
}
@@ -9279,7 +8630,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);
}
@@ -9289,15 +8640,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);
}
@@ -9317,54 +8668,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);
}
@@ -9387,7 +8741,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
@@ -9401,29 +8755,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;
}
@@ -9435,97 +8789,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
}
@@ -9540,34 +8894,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);
@@ -9583,26 +8937,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);
@@ -9652,227 +9005,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);
@@ -9884,64 +9236,65 @@ parse_qmark(struct parser_params *p, int space_seen)
rb_encoding *enc;
register int c;
VALUE lit;
- const char *start = p->lex.pcur;
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;
- int w = parser_precise_mbclen(p, start);
- if (is_identchar(p, start, p->lex.pend, p->enc) &&
- !(lex_eol_ptr_n_p(p, start, w) || !is_identchar(p, start + w, p->lex.pend, p->enc))) {
- if (space_seen) {
- const char *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;
+ if (!parser_isascii(p)) {
+ if (tokadd_mbchar(p, c) == -1) return 0;
+ }
+ else if ((rb_enc_isalnum(c, p->enc) || c == '_') &&
+ 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);
- }
- 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);
- }
+ if (peek(p, 'u')) {
+ nextc(p);
+ enc = rb_utf8_encoding();
+ tokadd_utf8(p, &enc, -1, 0, 0);
+ }
+ else if (!lex_eol_p(p) && !(c = *p->lex.pcur, ISASCII(c))) {
+ nextc(p);
+ if (tokadd_mbchar(p, c) == -1) return 0;
+ }
+ else {
+ c = read_escape(p, 0, &enc);
+ tokadd(p, c);
+ }
}
else {
- if (tokadd_mbchar(p, c) == -1) return 0;
+ tokadd(p, c);
}
tokfix(p);
lit = STR_NEW3(tok(p), toklen(p), enc, 0);
@@ -9957,92 +9310,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);
@@ -10053,15 +9406,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();
@@ -10077,17 +9430,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;
}
}
@@ -10103,106 +9456,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;
}
@@ -10213,18 +9560,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;
}
@@ -10242,42 +9589,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;
}
@@ -10291,117 +9638,117 @@ 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 */
- (lvar_defined(p, ident) || NUMPARAM_ID_P(ident))) {
- SET_LEX_STATE(EXPR_END|EXPR_LABEL);
+ (result == tIDENTIFIER) && /* not EXPR_FNAME, not attrasgn */
+ lvar_defined(p, ident)) {
+ SET_LEX_STATE(EXPR_END|EXPR_LABEL);
}
return result;
}
@@ -10410,9 +9757,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");
}
}
@@ -10428,14 +9775,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;
@@ -10450,687 +9797,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)) {
- enum yytokentype 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);
@@ -11148,9 +10494,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;
}
@@ -11158,11 +10504,14 @@ 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_newnode(struct parser_params *p, enum node_type type, VALUE a0, VALUE a1, VALUE a2, const rb_code_location_t *loc)
{
- NODE *n = rb_ast_newnode(p->ast, type, size, alignment);
+ NODE *n = rb_ast_newnode(p->ast, type);
+
+ rb_node_init(n, type, a0, a1, a2);
- rb_node_init(n, type);
+ nd_set_loc(n, loc);
+ nd_set_node_id(n, parser_get_node_id(p));
return n;
}
@@ -11174,1107 +10523,6 @@ nd_set_loc(NODE *nd, const YYLTYPE *loc)
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 *n = node_new_internal(p, type, size, alignment);
-
- 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 = (NODE *)n;
- 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)
-{
- 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 = 0;
- n->save.max_numparam = 0;
- 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;
-}
-
-static rb_node_def_temp_t *
-def_head_save(struct parser_params *p, rb_node_def_temp_t *n)
-{
- n->save.numparam_save = numparam_push(p);
- n->save.max_numparam = p->max_numparam;
- return n;
-}
-
#ifndef RIPPER
static enum node_type
nodetype(NODE *node) /* for debug */
@@ -12292,8 +10540,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;
}
@@ -12327,36 +10575,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);
- 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);
+ 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;
}
@@ -12368,16 +10626,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));
@@ -12390,20 +10648,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));
@@ -12416,26 +10674,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;
}
@@ -12452,110 +10710,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;
}
@@ -12566,14 +10802,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);
}
@@ -12589,7 +10826,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);
@@ -12628,15 +10865,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;
- 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)
{
@@ -12645,38 +10874,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);
@@ -12690,8 +10918,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;
}
@@ -12704,13 +10932,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;
}
@@ -12722,107 +10950,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 */
- if (dyna_in_block(p) && id == rb_intern("it")
- && !(DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev))
- && p->max_numparam != ORDINAL_PARAM) {
- rb_warn0("`it` calls without arguments will refer to the first block param in Ruby 3.4; use it() or self.it");
- }
- 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;
}
@@ -12830,49 +11052,23 @@ kwd_append(rb_node_kw_arg_t *kwlist, rb_node_kw_arg_t *kw)
static NODE *
new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc)
{
- NODE *n = expr;
- while (n) {
- if (nd_type_p(n, NODE_BEGIN)) {
- n = RNODE_BEGIN(n)->nd_body;
- }
- else if (nd_type_p(n, NODE_BLOCK) && RNODE_BLOCK(n)->nd_end == n) {
- n = RNODE_BLOCK(n)->nd_head;
- }
- else {
- break;
- }
- }
- return NEW_DEFINED(n, loc);
-}
-
-static VALUE
-str_to_sym_check(struct parser_params *p, VALUE lit, const YYLTYPE *loc)
-{
- if (rb_enc_str_coderange(lit) == ENC_CODERANGE_BROKEN) {
- yyerror1(loc, "invalid symbol");
- lit = STR_NEW0();
- }
-
- return lit;
+ return NEW_DEFINED(remove_begin_all(expr), loc);
}
static NODE*
symbol_append(struct parser_params *p, NODE *symbols, NODE *symbol)
{
- VALUE lit;
-
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);
- lit = str_to_sym_check(p, RNODE_LIT(symbol)->nd_lit, &RNODE(symbol)->nd_loc);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(symbol)->nd_lit = rb_str_intern(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);
}
@@ -12880,99 +11076,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;
- VALUE re = reg_compile(p, src, options);
- RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_DREGX(node)->nd_lit = re);
- }
- 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;
}
@@ -12987,19 +11182,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));
}
@@ -13009,17 +11204,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;
@@ -13028,18 +11223,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);
}
@@ -13049,7 +11244,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;
}
@@ -13062,23 +11257,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;
}
@@ -13089,53 +11284,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);
}
@@ -13153,16 +11348,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;
}
@@ -13181,7 +11376,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);
@@ -13240,55 +11435,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;
}
@@ -13308,7 +11503,7 @@ assignable(struct parser_params *p, ID id, NODE *val, const YYLTYPE *loc)
case NODE_CVASGN: return NEW_CVASGN(id, val, loc);
}
if (err) yyerror1(loc, err);
- return NEW_ERROR(loc);
+ return NEW_BEGIN(0, loc);
}
#else
static VALUE
@@ -13322,7 +11517,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;
@@ -13336,23 +11531,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;
}
@@ -13369,9 +11564,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);
@@ -13388,7 +11583,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");
}
}
@@ -13404,11 +11599,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
@@ -13416,7 +11611,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
@@ -13428,20 +11623,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);
@@ -13453,21 +11648,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);
}
@@ -13477,7 +11672,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);
}
@@ -13487,7 +11682,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);
}
@@ -13495,7 +11690,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;
}
@@ -13507,62 +11702,64 @@ 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
}
}
static NODE *
-const_decl_path(struct parser_params *p, NODE *dest)
+const_decl_path(struct parser_params *p, NODE **dest)
{
- NODE *n = 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);
- }
- 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)
{
@@ -13583,28 +11780,28 @@ ensure_shareable_node(struct parser_params *p, NODE **dest, NODE *value, const Y
{
NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, loc);
NODE *args = NEW_LIST(value, loc);
- args = list_append(p, args, const_decl_path(p, *dest));
+ args = list_append(p, args, const_decl_path(p, dest));
return NEW_CALL(fcore, rb_intern("ensure_shareable"), args, loc);
}
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;
}
}
@@ -13614,7 +11811,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)
@@ -13627,112 +11824,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;
@@ -13741,32 +11938,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);
}
}
@@ -13777,8 +11974,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:
@@ -13786,18 +11983,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;
@@ -13809,67 +12006,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;
@@ -13880,13 +12077,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)
{
@@ -13897,29 +12093,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:
@@ -13928,46 +12124,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));
}
}
@@ -13979,9 +12175,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;
}
@@ -13990,8 +12186,18 @@ 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;
+}
+
+static NODE *
+remove_begin_all(NODE *node)
+{
+ NODE **n = &node, *n1 = node;
+ while (n1 && nd_type_p(n1, NODE_BEGIN)) {
+ *n = n1 = n1->nd_body;
}
return node;
}
@@ -14002,58 +12208,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
@@ -14065,20 +12270,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;
}
@@ -14092,18 +12297,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;
}
@@ -14114,15 +12317,14 @@ 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*,bool);
+static NODE *cond0(struct parser_params*,NODE*,enum cond_type,const YYLTYPE*);
static NODE*
range_op(struct parser_params *p, NODE *node, const YYLTYPE *loc)
@@ -14133,83 +12335,69 @@ 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, true);
+ return cond0(p, node, COND_IN_FF, loc);
}
static NODE*
-cond0(struct parser_params *p, NODE *node, enum cond_type type, const YYLTYPE *loc, bool top)
+cond0(struct parser_params *p, NODE *node, enum cond_type type, const YYLTYPE *loc)
{
if (node == 0) return 0;
if (!(node = nd_once_body(node))) return 0;
assign_in_cond(p, node);
switch (nd_type(node)) {
- case NODE_BEGIN:
- RNODE_BEGIN(node)->nd_body = cond0(p, RNODE_BEGIN(node)->nd_body, type, loc, top);
- break;
-
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:
- {
- NODE *end = RNODE_BLOCK(node)->nd_end;
- NODE **expr = &RNODE_BLOCK(end)->nd_head;
- if (top) top = node == end;
- *expr = cond0(p, *expr, type, loc, top);
- }
- 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, true);
- RNODE_AND(node)->nd_2nd = cond0(p, RNODE_AND(node)->nd_2nd, COND_IN_COND, loc, true);
- 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:
- if (!top) break;
- 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;
}
@@ -14218,14 +12406,14 @@ static NODE*
cond(struct parser_params *p, NODE *node, const YYLTYPE *loc)
{
if (node == 0) return 0;
- return cond0(p, node, COND_IN_COND, loc, true);
+ return cond0(p, node, COND_IN_COND, loc);
}
static NODE*
method_cond(struct parser_params *p, NODE *node, const YYLTYPE *loc)
{
if (node == 0) return 0;
- return cond0(p, node, COND_IN_OP, loc, true);
+ return cond0(p, node, COND_IN_OP, loc);
}
static NODE*
@@ -14239,7 +12427,7 @@ static NODE*
new_if(struct parser_params *p, NODE *cc, NODE *left, NODE *right, const YYLTYPE *loc)
{
if (!cc) return right;
- cc = cond0(p, cc, COND_IN_COND, loc, true);
+ cc = cond0(p, cc, COND_IN_COND, loc);
return newline_node(NEW_IF(cc, left, right, loc));
}
@@ -14247,41 +12435,37 @@ static NODE*
new_unless(struct parser_params *p, NODE *cc, NODE *left, NODE *right, const YYLTYPE *loc)
{
if (!cc) return right;
- cc = cond0(p, cc, COND_IN_COND, loc, true);
+ cc = cond0(p, cc, COND_IN_COND, loc);
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");
}
}
@@ -14289,10 +12473,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;
}
@@ -14309,49 +12498,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;
}
@@ -14369,17 +12558,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;
@@ -14399,78 +12589,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;
}
@@ -14478,76 +12677,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;
}
@@ -14557,23 +12786,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 = str_to_sym_check(p, RNODE_STR(node)->nd_lit, &RNODE(node)->nd_loc);
- 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;
}
@@ -14583,60 +12812,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;
@@ -14653,14 +12905,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);
}
}
@@ -14668,11 +12920,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);
}
@@ -14692,65 +12944,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_ERROR(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;
@@ -14765,11 +13031,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_ERROR(loc);
+ asgn = NEW_BEGIN(0, loc);
}
fixpos(asgn, lhs);
return asgn;
@@ -14779,7 +13045,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);
}
@@ -14788,7 +13054,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;
}
@@ -14839,15 +13105,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
}
@@ -14881,43 +13147,26 @@ local_push(struct parser_params *p, int toplevel_scope)
}
static void
-vtable_chain_free(struct parser_params *p, struct vtable *table)
-{
- while (!DVARS_TERMINAL_P(table)) {
- struct vtable *cur_table = table;
- table = cur_table->prev;
- vtable_free(cur_table);
- }
-}
-
-static void
-local_free(struct parser_params *p, struct local_vars *local)
-{
- vtable_chain_free(p, local->used);
-
-# if WARN_PAST_SCOPE
- vtable_chain_free(p, local->past);
-# endif
-
- vtable_chain_free(p, local->args);
- vtable_chain_free(p, local->vars);
-
- ruby_sized_xfree(local, sizeof(struct local_vars));
-}
-
-static void
local_pop(struct parser_params *p)
{
struct local_vars *local = p->lvtbl->prev;
if (p->lvtbl->used) {
- warn_unused_var(p, p->lvtbl);
+ warn_unused_var(p, p->lvtbl);
+ vtable_free(p->lvtbl->used);
}
-
- local_free(p, p->lvtbl);
- p->lvtbl = local;
-
+# if WARN_PAST_SCOPE
+ while (p->lvtbl->past) {
+ struct vtable *past = p->lvtbl->past;
+ p->lvtbl->past = past->prev;
+ vtable_free(past);
+ }
+# endif
+ vtable_free(p->lvtbl->args);
+ vtable_free(p->lvtbl->vars);
CMDARG_POP();
COND_POP();
+ ruby_sized_xfree(p->lvtbl, sizeof(*p->lvtbl));
+ p->lvtbl = local;
}
#ifndef RIPPER
@@ -14935,10 +13184,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);
@@ -14947,6 +13196,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
@@ -14970,7 +13230,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);
}
}
@@ -14984,21 +13244,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;
}
}
@@ -15027,40 +13287,6 @@ add_forwarding_args(struct parser_params *p)
arg_var(p, idFWD_ALL);
}
-static void
-forwarding_arg_check(struct parser_params *p, ID arg, ID all, const char *var)
-{
- bool conflict = false;
-
- struct vtable *vars, *args;
-
- vars = p->lvtbl->vars;
- args = p->lvtbl->args;
-
- while (vars && !DVARS_TERMINAL_P(vars->prev)) {
- conflict |= (vtable_included(args, arg) && !(all && vtable_included(args, all)));
- vars = vars->prev;
- args = args->prev;
- }
-
- bool found = false;
- if (vars && vars->prev == DVARS_INHERIT && !found) {
- found = (rb_local_defined(arg, p->parent_iseq) &&
- !(all && rb_local_defined(all, p->parent_iseq)));
- }
- else {
- found = (vtable_included(args, arg) &&
- !(all && vtable_included(args, all)));
- }
-
- if (!found) {
- compile_error(p, "no anonymous %s parameter", var);
- }
- else if (conflict) {
- compile_error(p, "anonymous %s parameter is also used within block", var);
- }
-}
-
#ifndef RIPPER
static NODE *
new_args_forward_call(struct parser_params *p, NODE *leading, const YYLTYPE *loc, const YYLTYPE *argsloc)
@@ -15069,7 +13295,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);
@@ -15085,7 +13311,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;
@@ -15101,21 +13327,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
}
@@ -15126,7 +13352,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;
}
@@ -15138,9 +13364,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);
@@ -15152,9 +13378,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);
@@ -15164,12 +13390,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);
}
@@ -15191,17 +13417,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)) {
@@ -15221,7 +13447,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
@@ -15239,13 +13465,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) &&
@@ -15253,16 +13479,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;
@@ -15286,12 +13512,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;
@@ -15308,8 +13533,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 *
@@ -15324,31 +13564,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_ERROR(loc);
- succ = block_append(p, succ, node);
- *succ_block = succ;
- return ST_CONTINUE;
+ return arg.succ_block->nd_next;
}
static VALUE
@@ -15373,10 +13589,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;
}
@@ -15386,13 +13602,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;
}
@@ -15400,8 +13616,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;
@@ -15415,32 +13633,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;
@@ -15470,7 +13688,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;
@@ -15483,17 +13700,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;
@@ -15501,11 +13716,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);
@@ -15521,47 +13738,32 @@ 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);
}
-
for (local = p->lvtbl; local; local = prev) {
- prev = local->prev;
- local_free(p, local);
+ if (local->vars) xfree(local->vars);
+ prev = local->prev;
+ xfree(local);
}
-
{
- token_info *ptinfo;
- while ((ptinfo = p->token_info) != 0) {
- p->token_info = ptinfo->next;
- xfree(ptinfo);
- }
+ token_info *ptinfo;
+ while ((ptinfo = p->token_info) != 0) {
+ p->token_info = ptinfo->next;
+ xfree(ptinfo);
+ }
}
-
- xfree(p->lex.strterm);
- p->lex.strterm = 0;
-
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;
@@ -15569,39 +13771,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
@@ -15612,361 +13800,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)
-{
- 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)
+rb_parser_get_debug_output(VALUE self)
{
- 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
@@ -15975,7 +13982,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)
@@ -16004,13 +14011,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);
@@ -16023,11 +14030,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
@@ -16042,35 +14049,26 @@ rb_parser_printf(struct parser_params *p, const char *fmt, ...)
va_start(ap, fmt);
rb_str_vcatf(mesg, fmt, ap);
va_end(ap);
- if (end_with_newline_p(p, mesg)) {
- rb_io_write(p->debug_output, mesg);
- p->debug_buffer = Qnil;
+ if (RSTRING_END(mesg)[-1] == '\n') {
+ 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);
}
@@ -16092,58 +14090,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: ;
}
@@ -16163,7 +14161,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)) {
@@ -16174,20 +14172,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;
}
@@ -16259,21 +14257,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 17f669e763..0000000000
--- a/parser_st.c
+++ /dev/null
@@ -1,164 +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
-#define rb_st_add_direct_with_hash rb_parser_st_add_direct_with_hash
-#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 d3b6b08709..0000000000
--- a/prism/config.yml
+++ /dev/null
@@ -1,2704 +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: CONTAINS_KEYWORD_SPLAT
- comment: "if arguments contain keyword splat"
- comment: Flags for arguments nodes.
- - name: ArrayNodeFlags
- values:
- - name: CONTAINS_SPLAT
- comment: "if array contains splat nodes"
- comment: Flags for array nodes.
- - name: CallNodeFlags
- values:
- - name: SAFE_NAVIGATION
- comment: "&. operator"
- - name: VARIABLE_CALL
- comment: "a call that could have been a local variable"
- - name: ATTRIBUTE_WRITE
- comment: "a call that is an attribute write, so the value being written should be returned"
- comment: Flags for call nodes.
- - name: EncodingFlags
- values:
- - name: FORCED_UTF8_ENCODING
- comment: "internal bytes forced the encoding to UTF-8"
- - name: FORCED_BINARY_ENCODING
- comment: "internal bytes forced the encoding to binary"
- comment: Flags for nodes that have unescaped content.
- - name: IntegerBaseFlags
- values:
- - name: BINARY
- comment: "0b prefix"
- - name: DECIMAL
- comment: "0d or no prefix"
- - name: OCTAL
- comment: "0o or 0 prefix"
- - name: HEXADECIMAL
- comment: "0x prefix"
- comment: Flags for integer nodes that correspond to the base of the integer.
- - name: KeywordHashNodeFlags
- values:
- - name: STATIC_KEYS
- comment: "a keyword hash which only has `AssocNode` elements all with static literal keys, which means the elements can be treated as keyword arguments"
- comment: Flags for keyword hash nodes.
- - 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"
- - name: FORCED_UTF8_ENCODING
- comment: "internal bytes forced the encoding to UTF-8"
- - name: FORCED_BINARY_ENCODING
- comment: "internal bytes forced the encoding to binary"
- - name: FORCED_US_ASCII_ENCODING
- comment: "internal bytes forced the encoding to US-ASCII"
- comment: Flags for regular expression and match last line nodes.
- - name: StringFlags
- values:
- - name: FORCED_UTF8_ENCODING
- comment: "internal bytes forced the encoding to UTF-8"
- - name: FORCED_BINARY_ENCODING
- comment: "internal bytes forced the encoding to binary"
- - name: FROZEN
- comment: "frozen by virtue of a `frozen_string_literal` comment"
- comment: Flags for string nodes.
- - name: SymbolFlags
- values:
- - name: FORCED_UTF8_ENCODING
- comment: "internal bytes forced the encoding to UTF-8"
- - name: FORCED_BINARY_ENCODING
- comment: "internal bytes forced the encoding to binary"
- - name: FORCED_US_ASCII_ENCODING
- comment: "internal bytes forced the encoding to US-ASCII"
- comment: Flags for symbol 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: flags
- type: flags
- kind: ArgumentsNodeFlags
- - name: arguments
- type: node[]
- comment: |
- Represents a set of arguments to a method or a keyword.
-
- return foo, bar, baz
- ^^^^^^^^^^^^^
- - name: ArrayNode
- fields:
- - name: flags
- type: flags
- kind: ArrayNodeFlags
- - 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: locals_body_index
- type: uint32
- - name: parameters
- type: node?
- - 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: flags
- type: flags
- kind: CallNodeFlags
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - 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: flags
- type: flags
- kind: CallNodeFlags
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: name
- type: constant
- - 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?
- 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: flags
- type: flags
- kind: CallNodeFlags
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - 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: flags
- type: flags
- kind: CallNodeFlags
- - name: receiver
- type: node?
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - 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: CallTargetNode
- fields:
- - name: flags
- type: flags
- kind: CallNodeFlags
- - name: receiver
- type: node
- - name: call_operator_loc
- type: location
- - name: name
- type: constant
- - name: message_loc
- type: location
- comment: |
- Represents assigning to a method call.
-
- foo.bar, = 1
- ^^^^^^^
-
- begin
- rescue => foo.bar
- ^^^^^^^
- end
-
- for foo.bar in baz do end
- ^^^^^^^
- - 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: CaseMatchNode
- 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 for pattern matching.
-
- case true
- in false
- end
- ^^^^^^^^^
- - 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: locals_body_index
- type: uint32
- - 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: flags
- type: flags
- kind: RangeFlags
- - name: left
- type: node?
- - name: right
- type: node?
- - name: operator_loc
- type: location
- 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: then_keyword_loc
- type: location?
- - 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: ImplicitRestNode
- comment: |
- Represents using a trailing comma to indicate an implicit rest parameter.
-
- foo { |bar,| }
- ^
-
- foo in [bar,]
- ^
-
- for foo, in bar do end
- ^
-
- foo, = bar
- ^
- - 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: flags
- type: flags
- kind: CallNodeFlags
- - 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: 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: flags
- type: flags
- kind: CallNodeFlags
- - 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: 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: flags
- type: flags
- kind: CallNodeFlags
- - 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: operator_loc
- type: location
- - name: value
- type: node
- comment: |
- Represents the use of the `||=` operator on a call to `[]`.
-
- foo.bar[baz] ||= value
- ^^^^^^^^^^^^^^^^^^^^^^
- - name: IndexTargetNode
- fields:
- - name: flags
- type: flags
- kind: CallNodeFlags
- - name: receiver
- type: node
- - name: opening_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location
- - name: block
- type: node?
- comment: |
- Represents assigning to an index.
-
- foo[bar], = 1
- ^^^^^^^^
-
- begin
- rescue => foo[bar]
- ^^^^^^^^
- end
-
- for foo[bar] in baz do end
- ^^^^^^^^
- - 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: flags
- type: flags
- kind: RegularExpressionFlags
- - name: opening_loc
- type: location
- - name: parts
- type: node[]
- - name: closing_loc
- type: location
- 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: flags
- type: flags
- kind: RegularExpressionFlags
- - name: opening_loc
- type: location
- - name: parts
- type: node[]
- - name: closing_loc
- type: location
- 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: flags
- type: flags
- kind: KeywordHashNodeFlags
- - 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: locals_body_index
- type: uint32
- - name: operator_loc
- type: location
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- - name: parameters
- type: node?
- - 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: flags
- type: flags
- kind: RegularExpressionFlags
- - name: opening_loc
- type: location
- - name: content_loc
- type: location
- - name: closing_loc
- type: location
- - name: unescaped
- type: string
- 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: targets
- type: node[]
- 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: NumberedParametersNode
- fields:
- - name: maximum
- type: uint8
- comment: |
- Represents an implicit set of parameters through the use of numbered
- parameters within a block or lambda.
-
- -> { _1 + _2 }
- ^^^^^^^^^^^^^^
- - 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?
- - 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: flags
- type: flags
- kind: RangeFlags
- - name: left
- type: node?
- - name: right
- type: node?
- - name: operator_loc
- type: location
- 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: flags
- type: flags
- kind: RegularExpressionFlags
- - name: opening_loc
- type: location
- - name: content_loc
- type: location
- - name: closing_loc
- type: location
- - name: unescaped
- type: string
- 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: 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: flags
- type: flags
- kind: SymbolFlags
- - 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: then_keyword_loc
- type: location?
- - 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: flags
- type: flags
- kind: LoopFlags
- - name: keyword_loc
- type: location
- - name: closing_loc
- type: location?
- - name: predicate
- type: node
- - name: statements
- type: node?
- kind: StatementsNode
- 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: flags
- type: flags
- kind: LoopFlags
- - name: keyword_loc
- type: location
- - name: closing_loc
- type: location?
- - name: predicate
- type: node
- - name: statements
- type: node?
- kind: StatementsNode
- 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: flags
- type: flags
- kind: EncodingFlags
- - 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 c9715c4eb0..0000000000
--- a/prism/defines.h
+++ /dev/null
@@ -1,94 +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
-
-/**
- * A simple utility macro to concatenate two tokens together, necessary when one
- * of the tokens is itself a macro.
- */
-#define PM_CONCATENATE(left, right) left ## right
-
-/**
- * We want to be able to use static assertions, but they weren't standardized
- * until C11. As such, we polyfill it here by making a hacky typedef that will
- * fail to compile due to a negative array size if the condition is false.
- */
-#if defined(_Static_assert)
-# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message)
-#else
-# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1]
-#endif
-
-#endif
diff --git a/prism/diagnostic.c b/prism/diagnostic.c
deleted file mode 100644
index 1fc8c50cb5..0000000000
--- a/prism/diagnostic.c
+++ /dev/null
@@ -1,355 +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"
- * - Do not 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_AFTER_FORWARDING_ELLIPSES] = "unexpected argument after `...`",
- [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_FORWARDING_UNBOUND] = "unexpected `...` in an non-parenthesized call",
- [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_MATCH_MISSING_PREDICATE] = "expected a predicate for a case matching statement",
- [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 definition",
- [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_MIXED_ENCODING] = "UTF-8 mixed within %s source",
- [PM_ERR_MODULE_IN_METHOD] = "unexpected module definition in a method definition",
- [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 when an ordinary parameter is defined",
- [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_CIRCULAR] = "parameter default value references itself",
- [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] = "%.2s is reserved for numbered parameters",
- [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_EXPRESSION_AFTER_REST] = "unexpected pattern expression after the `**` expression",
- [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_STATEMENT_ALIAS] = "unexpected an `alias` at a non-statement position",
- [PM_ERR_STATEMENT_POSTEXE_END] = "unexpected an `END` at a non-statement position",
- [PM_ERR_STATEMENT_PREEXE_BEGIN] = "unexpected a `BEGIN` at a non-statement position",
- [PM_ERR_STATEMENT_UNDEF] = "unexpected an `undef` at a non-statement position",
- [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_VOID_EXPRESSION] = "unexpected void value expression",
- [PM_ERR_WHILE_TERM] = "expected an `end` to close the `while` statement",
- [PM_ERR_WRITE_TARGET_IN_METHOD] = "dynamic constant assignment",
- [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",
- [PM_WARN_END_IN_METHOD] = "END in method; use at_exit",
-};
-
-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) {
- .location = { start, end },
- .message = pm_diagnostic_message(diag_id),
- .owned = false
- };
-
- pm_list_append(list, (pm_list_node_t *) diagnostic);
- return true;
-}
-
-/**
- * Append a diagnostic to the given list of diagnostics that is using a format
- * string for its message.
- */
-bool
-pm_diagnostic_list_append_format(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id, ...) {
- va_list arguments;
- va_start(arguments, diag_id);
-
- const char *format = pm_diagnostic_message(diag_id);
- int result = vsnprintf(NULL, 0, format, arguments);
- va_end(arguments);
-
- if (result < 0) {
- return false;
- }
-
- pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) calloc(sizeof(pm_diagnostic_t), 1);
- if (diagnostic == NULL) {
- return false;
- }
-
- size_t length = (size_t) (result + 1);
- char *message = (char *) malloc(length);
- if (message == NULL) {
- free(diagnostic);
- return false;
- }
-
- va_start(arguments, diag_id);
- vsnprintf(message, length, format, arguments);
- va_end(arguments);
-
- *diagnostic = (pm_diagnostic_t) {
- .location = { start, end },
- .message = message,
- .owned = true
- };
-
- 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;
-
- if (diagnostic->owned) free((void *) diagnostic->message);
- free(diagnostic);
- }
-}
diff --git a/prism/diagnostic.h b/prism/diagnostic.h
deleted file mode 100644
index fc1f0c2b4b..0000000000
--- a/prism/diagnostic.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/**
- * @file diagnostic.h
- *
- * A list of diagnostics generated during parsing.
- */
-#ifndef PRISM_DIAGNOSTIC_H
-#define PRISM_DIAGNOSTIC_H
-
-#include "prism/ast.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;
-
- /** The location of the diagnostic in the source. */
- pm_location_t location;
-
- /** The message associated with the diagnostic. */
- const char *message;
-
- /**
- * Whether or not the memory related to the message of this diagnostic is
- * owned by this diagnostic. If it is, it needs to be freed when the
- * diagnostic is freed.
- */
- bool owned;
-} 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_AFTER_FORWARDING_ELLIPSES,
- 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_FORWARDING_UNBOUND,
- 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_MATCH_MISSING_PREDICATE,
- 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_MIXED_ENCODING,
- 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_CIRCULAR,
- 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_EXPRESSION_AFTER_REST,
- 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_STATEMENT_ALIAS,
- PM_ERR_STATEMENT_POSTEXE_END,
- PM_ERR_STATEMENT_PREEXE_BEGIN,
- PM_ERR_STATEMENT_UNDEF,
- 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_VOID_EXPRESSION,
- PM_ERR_WHILE_TERM,
- PM_ERR_WRITE_TARGET_IN_METHOD,
- 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,
- PM_WARN_END_IN_METHOD,
-
- /* This must be the last member. */
- PM_DIAGNOSTIC_ID_LEN,
-} pm_diagnostic_id_t;
-
-/**
- * Append a diagnostic to the given list of diagnostics that is using shared
- * memory for its message.
- *
- * @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);
-
-/**
- * Append a diagnostic to the given list of diagnostics that is using a format
- * string for its message.
- *
- * @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.
- * @param ... The arguments to the format string for the message.
- * @return Whether the diagnostic was successfully appended.
- */
-bool pm_diagnostic_list_append_format(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/encoding.c b/prism/encoding.c
deleted file mode 100644
index 2c6d7c9777..0000000000
--- a/prism/encoding.c
+++ /dev/null
@@ -1,5137 +0,0 @@
-#include "prism/encoding.h"
-
-typedef uint32_t pm_unicode_codepoint_t;
-
-#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,
-};
-
-/**
- * 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
-};
-
-/**
- * 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;
- }
-}
-
-static pm_unicode_codepoint_t
-pm_cesu_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
- if (b[0] < 0x80) {
- *width = 1;
- return (pm_unicode_codepoint_t) b[0];
- }
-
- if (n > 1 && b[0] >= 0xC2 && b[0] <= 0xDF && b[1] >= 0x80 && b[1] <= 0xBF) {
- *width = 2;
-
- // 110xxxxx 10xxxxxx
- return (pm_unicode_codepoint_t) (((b[0] & 0x1F) << 6) | (b[1] & 0x3F));
- }
-
- if (n > 5 && b[0] == 0xED && b[1] >= 0xA0 && b[1] <= 0xAF && b[2] >= 0x80 && b[2] <= 0xBF && b[3] == 0xED && b[4] >= 0xB0 && b[4] <= 0xBF && b[5] >= 0x80 && b[5] <= 0xBF) {
- *width = 6;
-
- // 11101101 1010xxxx 10xxxxxx 11101101 1011xxxx 10xxxxxx
- return (pm_unicode_codepoint_t) (0x10000 + (((b[1] & 0xF) << 16) | ((b[2] & 0x3F) << 10) | ((b[4] & 0xF) << 6) | (b[5] & 0x3F)));
- }
-
- if (n > 2 && b[0] == 0xED && b[1] >= 0xA0 && b[1] <= 0xBF) {
- *width = 3;
-
- // 11101101 1010xxxx 10xxxxx
- return (pm_unicode_codepoint_t) (0x10000 + (((b[0] & 0x03) << 16) | ((b[1] & 0x3F) << 10) | (b[2] & 0x3F)));
- }
-
- if (n > 2 && ((b[0] == 0xE0 && b[1] >= 0xA0) || (b[0] >= 0xE1 && b[0] <= 0xEF && b[1] >= 0x80)) && b[1] <= 0xBF && b[2] >= 0x80 && b[2] <= 0xBF) {
- *width = 3;
-
- // 1110xxxx 10xxxxxx 10xxxxx
- return (pm_unicode_codepoint_t) (((b[0] & 0xF) << 12) | ((b[1] & 0x3F) << 6) | (b[2] & 0x3F));
- }
-
- *width = 0;
- return 0;
-}
-
-static size_t
-pm_encoding_cesu_8_char_width(const uint8_t *b, ptrdiff_t n) {
- size_t width;
- pm_cesu_8_codepoint(b, n, &width);
- return width;
-}
-
-static size_t
-pm_encoding_cesu_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_cesu_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;
- }
-}
-
-static size_t
-pm_encoding_cesu_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_cesu_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;
- }
-}
-
-static bool
-pm_encoding_cesu_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_cesu_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
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ASCII character.
- */
-static const 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 CP850 character.
- */
-static const uint8_t pm_encoding_cp850_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 CP852 character.
- */
-static const uint8_t pm_encoding_cp852_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 CP855 character.
- */
-static const uint8_t pm_encoding_cp855_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 GB1988 character.
- */
-static const uint8_t pm_encoding_gb1988_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 IBM437 character.
- */
-static const uint8_t pm_encoding_ibm437_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 IBM720 character.
- */
-static const uint8_t pm_encoding_ibm720_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 IBM737 character.
- */
-static const uint8_t pm_encoding_ibm737_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 IBM775 character.
- */
-static const uint8_t pm_encoding_ibm775_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 IBM852 character.
- */
-static const uint8_t pm_encoding_ibm852_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 IBM855 character.
- */
-static const uint8_t pm_encoding_ibm855_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 IBM857 character.
- */
-static const uint8_t pm_encoding_ibm857_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 IBM860 character.
- */
-static const uint8_t pm_encoding_ibm860_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 IBM861 character.
- */
-static const uint8_t pm_encoding_ibm861_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 IBM862 character.
- */
-static const uint8_t pm_encoding_ibm862_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 IBM863 character.
- */
-static const uint8_t pm_encoding_ibm863_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 IBM864 character.
- */
-static const uint8_t pm_encoding_ibm864_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 IBM865 character.
- */
-static const uint8_t pm_encoding_ibm865_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 IBM866 character.
- */
-static const uint8_t pm_encoding_ibm866_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 IBM869 character.
- */
-static const uint8_t pm_encoding_ibm869_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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 KOI8-U character.
- */
-static const uint8_t pm_encoding_koi8_u_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, 3, 0, 3, 3, 0, 0, 0, 0, 0, 3, 0, 0, // Ax
- 0, 0, 0, 7, 7, 0, 7, 7, 0, 0, 0, 0, 0, 7, 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 macCentEuro character.
- */
-static const uint8_t pm_encoding_mac_cent_euro_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 macCroatian character.
- */
-static const uint8_t pm_encoding_mac_croatian_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 macCyrillic character.
- */
-static const uint8_t pm_encoding_mac_cyrillic_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 macGreek character.
- */
-static const uint8_t pm_encoding_mac_greek_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 macIceland character.
- */
-static const uint8_t pm_encoding_mac_iceland_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 macRoman character.
- */
-static const uint8_t pm_encoding_mac_roman_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 macRomania character.
- */
-static const uint8_t pm_encoding_mac_romania_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 macThai character.
- */
-static const uint8_t pm_encoding_mac_thai_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 TIS-620 character.
- */
-static const uint8_t pm_encoding_tis_620_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 macTurkish character.
- */
-static const uint8_t pm_encoding_mac_turkish_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 macUkraine character.
- */
-static const uint8_t pm_encoding_mac_ukraine_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 windows-1250 character.
- */
-static const uint8_t pm_encoding_windows_1250_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, 7, 7, 7, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, // 9x
- 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 7, 0, 0, 0, 0, 7, // Ax
- 0, 0, 0, 3, 0, 3, 0, 0, 0, 3, 3, 0, 7, 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 windows-1251 character.
- */
-static const 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 const 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
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1253 character.
- */
-static const uint8_t pm_encoding_windows_1253_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, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 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 windows-1254 character.
- */
-static const uint8_t pm_encoding_windows_1254_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, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 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
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1255 character.
- */
-static const uint8_t pm_encoding_windows_1255_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 windows-1256 character.
- */
-static const uint8_t pm_encoding_windows_1256_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 windows-1257 character.
- */
-static const uint8_t pm_encoding_windows_1257_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 windows-1258 character.
- */
-static const uint8_t pm_encoding_windows_1258_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 windows-874 character.
- */
-static const uint8_t pm_encoding_windows_874_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
-};
-
-#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(cp850)
-PRISM_ENCODING_TABLE(cp852)
-PRISM_ENCODING_TABLE(cp855)
-PRISM_ENCODING_TABLE(gb1988)
-PRISM_ENCODING_TABLE(ibm437)
-PRISM_ENCODING_TABLE(ibm720)
-PRISM_ENCODING_TABLE(ibm737)
-PRISM_ENCODING_TABLE(ibm775)
-PRISM_ENCODING_TABLE(ibm852)
-PRISM_ENCODING_TABLE(ibm855)
-PRISM_ENCODING_TABLE(ibm857)
-PRISM_ENCODING_TABLE(ibm860)
-PRISM_ENCODING_TABLE(ibm861)
-PRISM_ENCODING_TABLE(ibm862)
-PRISM_ENCODING_TABLE(ibm863)
-PRISM_ENCODING_TABLE(ibm864)
-PRISM_ENCODING_TABLE(ibm865)
-PRISM_ENCODING_TABLE(ibm866)
-PRISM_ENCODING_TABLE(ibm869)
-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(koi8_u)
-PRISM_ENCODING_TABLE(mac_cent_euro)
-PRISM_ENCODING_TABLE(mac_croatian)
-PRISM_ENCODING_TABLE(mac_cyrillic)
-PRISM_ENCODING_TABLE(mac_greek)
-PRISM_ENCODING_TABLE(mac_iceland)
-PRISM_ENCODING_TABLE(mac_roman)
-PRISM_ENCODING_TABLE(mac_romania)
-PRISM_ENCODING_TABLE(mac_thai)
-PRISM_ENCODING_TABLE(mac_turkish)
-PRISM_ENCODING_TABLE(mac_ukraine)
-PRISM_ENCODING_TABLE(tis_620)
-PRISM_ENCODING_TABLE(windows_1250)
-PRISM_ENCODING_TABLE(windows_1251)
-PRISM_ENCODING_TABLE(windows_1252)
-PRISM_ENCODING_TABLE(windows_1253)
-PRISM_ENCODING_TABLE(windows_1254)
-PRISM_ENCODING_TABLE(windows_1255)
-PRISM_ENCODING_TABLE(windows_1256)
-PRISM_ENCODING_TABLE(windows_1257)
-PRISM_ENCODING_TABLE(windows_1258)
-PRISM_ENCODING_TABLE(windows_874)
-
-#undef PRISM_ENCODING_TABLE
-
-/**
- * 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.
- */
-static 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);
-}
-
-/**
- * Certain encodings are equivalent to ASCII below 0x80, so it works for our
- * purposes to have a function here that first checks the bounds and then falls
- * back to checking the ASCII lookup table.
- */
-static size_t
-pm_encoding_ascii_alpha_char_7bit(const uint8_t *b, ptrdiff_t n) {
- return (*b < 0x80) ? pm_encoding_ascii_alpha_char(b, n) : 0;
-}
-
-/**
- * Return the size of the next character in the ASCII encoding if it is an
- * alphanumeric character.
- */
-static 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;
-}
-
-/**
- * Certain encodings are equivalent to ASCII below 0x80, so it works for our
- * purposes to have a function here that first checks the bounds and then falls
- * back to checking the ASCII lookup table.
- */
-static size_t
-pm_encoding_ascii_alnum_char_7bit(const uint8_t *b, ptrdiff_t n) {
- return (*b < 0x80) ? pm_encoding_ascii_alnum_char(b, n) : 0;
-}
-
-/**
- * Return true if the next character in the ASCII encoding if it is an uppercase
- * character.
- */
-static 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);
-}
-
-/**
- * Certain encodings are equivalent to ASCII below 0x80, so it works for our
- * purposes to have a function here that first checks the bounds and then falls
- * back to checking the ASCII lookup table.
- */
-static bool
-pm_encoding_ascii_isupper_char_7bit(const uint8_t *b, ptrdiff_t n) {
- return (*b < 0x80) && pm_encoding_ascii_isupper_char(b, n);
-}
-
-/**
- * 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 Big5 encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-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] <= 0x7E) || (b[1] >= 0xA1 && b[1] <= 0xFE))) {
- return 2;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the CP949 encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_cp949_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] >= 0x81 && b[0] <= 0xfe) && (b[1] >= 0x41 && b[1] <= 0xfe)) {
- return 2;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the Emacs MULE encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_emacs_mule_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the 1 byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the 2 byte characters.
- if ((n > 1) && (b[0] >= 0x81 && b[0] <= 0x8F) && (b[1] >= 0xA0)) {
- return 2;
- }
-
- // These are the 3 byte characters.
- if (
- (n > 2) &&
- (
- ((b[0] >= 0x90 && b[0] <= 0x99) && (b[1] >= 0xA0)) ||
- ((b[0] == 0x9A || b[0] == 0x9B) && (b[1] >= 0xE0 && b[1] <= 0xEF))
- ) &&
- (b[2] >= 0xA0)
- ) {
- return 3;
- }
-
- // These are the 4 byte characters.
- if (
- (n > 3) &&
- (
- ((b[0] == 0x9C) && (b[1] >= 0xF0) && (b[1] <= 0xF4)) ||
- ((b[0] == 0x9D) && (b[1] >= 0xF5) && (b[1] <= 0xFE))
- ) &&
- (b[2] >= 0xA0) && (b[3] >= 0xA0)
- ) {
- return 4;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the EUC-JP encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-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[0] >= 0xA1 && b[0] <= 0xFE)) && (b[1] >= 0xA1 && b[1] <= 0xFE)) {
- return 2;
- }
-
- // These are the triple byte characters.
- if ((n > 2) && (b[0] == 0x8F) && (b[1] >= 0xA1 && b[2] <= 0xFE) && (b[2] >= 0xA1 && b[2] <= 0xFE)) {
- return 3;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the EUC-KR encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_euc_kr_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] >= 0xA1 && b[1] <= 0xFE)) {
- return 2;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the EUC-TW encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_euc_tw_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] >= 0xA1) && (b[1] <= 0xFE)) {
- return 2;
- }
-
- // These are the quadruple byte characters.
- if ((n > 3) && (b[0] == 0x8E) && (b[1] >= 0xA1) && (b[1] <= 0xB0) && (b[2] >= 0xA1) && (b[2] <= 0xFE) && (b[3] >= 0xA1) && (b[3] <= 0xFE)) {
- return 4;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the GB18030 encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_gb18030_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the 1 byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the 2 byte characters.
- if ((n > 1) && (b[0] >= 0x81 && b[0] <= 0xFE) && (b[1] >= 0x40 && b[1] <= 0xFE && b[1] != 0x7F)) {
- return 2;
- }
-
- // These are the 4 byte characters.
- if ((n > 3) && ((b[0] >= 0x81 && b[0] <= 0xFE) && (b[1] >= 0x30 && b[1] <= 0x39) && (b[2] >= 0x81 && b[2] <= 0xFE) && (b[3] >= 0x30 && b[3] <= 0x39))) {
- return 4;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the GBK encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-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
- ((b[0] >= 0xAA && b[0] <= 0xAF) && (b[1] >= 0xA1 && b[1] <= 0xFE)) || // user-defined 1
- ((b[0] >= 0xF8 && b[0] <= 0xFE) && (b[1] >= 0xA1 && b[1] <= 0xFE)) || // user-defined 2
- ((b[0] >= 0xA1 && b[0] <= 0xA7) && (b[1] >= 0x40 && b[1] <= 0xA0) && (b[1] != 0x7F)) // user-defined 3
- )
- ) {
- return 2;
- }
-
- return 0;
-}
-
-/**
- * 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_char_width(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return ((*b >= 0x20 && *b <= 0x7E) || (*b >= 0x80)) ? 1 : 0;
-}
-
-/**
- * Returns the size of the next character in the Shift_JIS encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-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;
-}
-
-/**
- * This is the table of all of the encodings that prism supports.
- */
-const pm_encoding_t pm_encodings[] = {
- [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
- },
- [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
- },
- [PM_ENCODING_BIG5] = {
- .name = "Big5",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_BIG5_HKSCS] = {
- .name = "Big5-HKSCS",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_BIG5_UAO] = {
- .name = "Big5-UAO",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_CESU_8] = {
- .name = "CESU-8",
- .char_width = pm_encoding_cesu_8_char_width,
- .alnum_char = pm_encoding_cesu_8_alnum_char,
- .alpha_char = pm_encoding_cesu_8_alpha_char,
- .isupper_char = pm_encoding_cesu_8_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_CP51932] = {
- .name = "CP51932",
- .char_width = pm_encoding_euc_jp_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_CP850] = {
- .name = "CP850",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_cp850_alnum_char,
- .alpha_char = pm_encoding_cp850_alpha_char,
- .isupper_char = pm_encoding_cp850_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_CP852] = {
- .name = "CP852",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_cp852_alnum_char,
- .alpha_char = pm_encoding_cp852_alpha_char,
- .isupper_char = pm_encoding_cp852_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_CP855] = {
- .name = "CP855",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_cp855_alnum_char,
- .alpha_char = pm_encoding_cp855_alpha_char,
- .isupper_char = pm_encoding_cp855_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_CP949] = {
- .name = "CP949",
- .char_width = pm_encoding_cp949_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_CP950] = {
- .name = "CP950",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_CP951] = {
- .name = "CP951",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_EMACS_MULE] = {
- .name = "Emacs-Mule",
- .char_width = pm_encoding_emacs_mule_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_EUC_JP] = {
- .name = "EUC-JP",
- .char_width = pm_encoding_euc_jp_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_EUC_JP_MS] = {
- .name = "eucJP-ms",
- .char_width = pm_encoding_euc_jp_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_EUC_JIS_2004] = {
- .name = "EUC-JIS-2004",
- .char_width = pm_encoding_euc_jp_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_EUC_KR] = {
- .name = "EUC-KR",
- .char_width = pm_encoding_euc_kr_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_EUC_TW] = {
- .name = "EUC-TW",
- .char_width = pm_encoding_euc_tw_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_GB12345] = {
- .name = "GB12345",
- .char_width = pm_encoding_euc_kr_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_GB18030] = {
- .name = "GB18030",
- .char_width = pm_encoding_gb18030_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_GB1988] = {
- .name = "GB1988",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_gb1988_alnum_char,
- .alpha_char = pm_encoding_gb1988_alpha_char,
- .isupper_char = pm_encoding_gb1988_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_GB2312] = {
- .name = "GB2312",
- .char_width = pm_encoding_euc_kr_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_GBK] = {
- .name = "GBK",
- .char_width = pm_encoding_gbk_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_IBM437] = {
- .name = "IBM437",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm437_alnum_char,
- .alpha_char = pm_encoding_ibm437_alpha_char,
- .isupper_char = pm_encoding_ibm437_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM720] = {
- .name = "IBM720",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm720_alnum_char,
- .alpha_char = pm_encoding_ibm720_alpha_char,
- .isupper_char = pm_encoding_ibm720_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM737] = {
- .name = "IBM737",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm737_alnum_char,
- .alpha_char = pm_encoding_ibm737_alpha_char,
- .isupper_char = pm_encoding_ibm737_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM775] = {
- .name = "IBM775",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm775_alnum_char,
- .alpha_char = pm_encoding_ibm775_alpha_char,
- .isupper_char = pm_encoding_ibm775_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM852] = {
- .name = "IBM852",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm852_alnum_char,
- .alpha_char = pm_encoding_ibm852_alpha_char,
- .isupper_char = pm_encoding_ibm852_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM855] = {
- .name = "IBM855",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm855_alnum_char,
- .alpha_char = pm_encoding_ibm855_alpha_char,
- .isupper_char = pm_encoding_ibm855_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM857] = {
- .name = "IBM857",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm857_alnum_char,
- .alpha_char = pm_encoding_ibm857_alpha_char,
- .isupper_char = pm_encoding_ibm857_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM860] = {
- .name = "IBM860",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm860_alnum_char,
- .alpha_char = pm_encoding_ibm860_alpha_char,
- .isupper_char = pm_encoding_ibm860_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM861] = {
- .name = "IBM861",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm861_alnum_char,
- .alpha_char = pm_encoding_ibm861_alpha_char,
- .isupper_char = pm_encoding_ibm861_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM862] = {
- .name = "IBM862",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm862_alnum_char,
- .alpha_char = pm_encoding_ibm862_alpha_char,
- .isupper_char = pm_encoding_ibm862_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM863] = {
- .name = "IBM863",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm863_alnum_char,
- .alpha_char = pm_encoding_ibm863_alpha_char,
- .isupper_char = pm_encoding_ibm863_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM864] = {
- .name = "IBM864",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm864_alnum_char,
- .alpha_char = pm_encoding_ibm864_alpha_char,
- .isupper_char = pm_encoding_ibm864_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM865] = {
- .name = "IBM865",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm865_alnum_char,
- .alpha_char = pm_encoding_ibm865_alpha_char,
- .isupper_char = pm_encoding_ibm865_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM866] = {
- .name = "IBM866",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm866_alnum_char,
- .alpha_char = pm_encoding_ibm866_alpha_char,
- .isupper_char = pm_encoding_ibm866_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM869] = {
- .name = "IBM869",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm869_alnum_char,
- .alpha_char = pm_encoding_ibm869_alpha_char,
- .isupper_char = pm_encoding_ibm869_isupper_char,
- .multibyte = false
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [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
- },
- [PM_ENCODING_KOI8_R] = {
- .name = "KOI8-R",
- .char_width = pm_encoding_koi8_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
- },
- [PM_ENCODING_KOI8_U] = {
- .name = "KOI8-U",
- .char_width = pm_encoding_koi8_char_width,
- .alnum_char = pm_encoding_koi8_u_alnum_char,
- .alpha_char = pm_encoding_koi8_u_alpha_char,
- .isupper_char = pm_encoding_koi8_u_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_CENT_EURO] = {
- .name = "macCentEuro",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_cent_euro_alnum_char,
- .alpha_char = pm_encoding_mac_cent_euro_alpha_char,
- .isupper_char = pm_encoding_mac_cent_euro_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_CROATIAN] = {
- .name = "macCroatian",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_croatian_alnum_char,
- .alpha_char = pm_encoding_mac_croatian_alpha_char,
- .isupper_char = pm_encoding_mac_croatian_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_CYRILLIC] = {
- .name = "macCyrillic",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_cyrillic_alnum_char,
- .alpha_char = pm_encoding_mac_cyrillic_alpha_char,
- .isupper_char = pm_encoding_mac_cyrillic_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_GREEK] = {
- .name = "macGreek",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_greek_alnum_char,
- .alpha_char = pm_encoding_mac_greek_alpha_char,
- .isupper_char = pm_encoding_mac_greek_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_ICELAND] = {
- .name = "macIceland",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_iceland_alnum_char,
- .alpha_char = pm_encoding_mac_iceland_alpha_char,
- .isupper_char = pm_encoding_mac_iceland_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_JAPANESE] = {
- .name = "MacJapanese",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_MAC_ROMAN] = {
- .name = "macRoman",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_roman_alnum_char,
- .alpha_char = pm_encoding_mac_roman_alpha_char,
- .isupper_char = pm_encoding_mac_roman_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_ROMANIA] = {
- .name = "macRomania",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_romania_alnum_char,
- .alpha_char = pm_encoding_mac_romania_alpha_char,
- .isupper_char = pm_encoding_mac_romania_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_THAI] = {
- .name = "macThai",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_thai_alnum_char,
- .alpha_char = pm_encoding_mac_thai_alpha_char,
- .isupper_char = pm_encoding_mac_thai_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_TURKISH] = {
- .name = "macTurkish",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_turkish_alnum_char,
- .alpha_char = pm_encoding_mac_turkish_alpha_char,
- .isupper_char = pm_encoding_mac_turkish_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_UKRAINE] = {
- .name = "macUkraine",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_ukraine_alnum_char,
- .alpha_char = pm_encoding_mac_ukraine_alpha_char,
- .isupper_char = pm_encoding_mac_ukraine_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_SHIFT_JIS] = {
- .name = "Shift_JIS",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_SJIS_DOCOMO] = {
- .name = "SJIS-DoCoMo",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_SJIS_KDDI] = {
- .name = "SJIS-KDDI",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_SJIS_SOFTBANK] = {
- .name = "SJIS-SoftBank",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_STATELESS_ISO_2022_JP] = {
- .name = "stateless-ISO-2022-JP",
- .char_width = pm_encoding_emacs_mule_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_STATELESS_ISO_2022_JP_KDDI] = {
- .name = "stateless-ISO-2022-JP-KDDI",
- .char_width = pm_encoding_emacs_mule_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_TIS_620] = {
- .name = "TIS-620",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_tis_620_alnum_char,
- .alpha_char = pm_encoding_tis_620_alpha_char,
- .isupper_char = pm_encoding_tis_620_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_US_ASCII] = {
- .name = "US-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
- },
- [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
- },
- [PM_ENCODING_UTF8_DOCOMO] = {
- .name = "UTF8-DoCoMo",
- .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
- },
- [PM_ENCODING_UTF8_KDDI] = {
- .name = "UTF8-KDDI",
- .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
- },
- [PM_ENCODING_UTF8_SOFTBANK] = {
- .name = "UTF8-SoftBank",
- .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
- },
- [PM_ENCODING_WINDOWS_1250] = {
- .name = "Windows-1250",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1250_alnum_char,
- .alpha_char = pm_encoding_windows_1250_alpha_char,
- .isupper_char = pm_encoding_windows_1250_isupper_char,
- .multibyte = false
- },
- [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
- },
- [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
- },
- [PM_ENCODING_WINDOWS_1253] = {
- .name = "Windows-1253",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1253_alnum_char,
- .alpha_char = pm_encoding_windows_1253_alpha_char,
- .isupper_char = pm_encoding_windows_1253_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1254] = {
- .name = "Windows-1254",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1254_alnum_char,
- .alpha_char = pm_encoding_windows_1254_alpha_char,
- .isupper_char = pm_encoding_windows_1254_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1255] = {
- .name = "Windows-1255",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1255_alnum_char,
- .alpha_char = pm_encoding_windows_1255_alpha_char,
- .isupper_char = pm_encoding_windows_1255_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1256] = {
- .name = "Windows-1256",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1256_alnum_char,
- .alpha_char = pm_encoding_windows_1256_alpha_char,
- .isupper_char = pm_encoding_windows_1256_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1257] = {
- .name = "Windows-1257",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1257_alnum_char,
- .alpha_char = pm_encoding_windows_1257_alpha_char,
- .isupper_char = pm_encoding_windows_1257_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1258] = {
- .name = "Windows-1258",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1258_alnum_char,
- .alpha_char = pm_encoding_windows_1258_alpha_char,
- .isupper_char = pm_encoding_windows_1258_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_31J] = {
- .name = "Windows-31J",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_WINDOWS_874] = {
- .name = "Windows-874",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_874_alnum_char,
- .alpha_char = pm_encoding_windows_874_alpha_char,
- .isupper_char = pm_encoding_windows_874_isupper_char,
- .multibyte = false
- }
-};
-
-/**
- * Parse the given name of an encoding and return a pointer to the corresponding
- * encoding struct if one can be found, otherwise return NULL.
- */
-const pm_encoding_t *
-pm_encoding_find(const uint8_t *start, const uint8_t *end) {
- size_t width = (size_t) (end - start);
-
- // First, we're going to check for UTF-8. This is the most common encoding.
- // UTF-8 can contain extra information at the end about the platform it is
- // encoded on, such as UTF-8-MAC or UTF-8-UNIX. We'll ignore those suffixes.
- if ((start + 5 <= end) && (pm_strncasecmp(start, (const uint8_t *) "UTF-8", 5) == 0)) {
- // We need to explicitly handle UTF-8-HFS, as that one needs to switch
- // over to being UTF8-MAC.
- if (width == 9 && (pm_strncasecmp(start + 5, (const uint8_t *) "-HFS", 4) == 0)) {
- return &pm_encodings[PM_ENCODING_UTF8_MAC];
- }
-
- // Otherwise we'll return the default UTF-8 encoding.
- return PM_ENCODING_UTF_8_ENTRY;
- }
-
- // 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 ENCODING1(name, encoding) if (width == sizeof(name) - 1 && pm_strncasecmp(start, (const uint8_t *) name, width) == 0) return &pm_encodings[encoding];
-#define ENCODING2(name1, name2, encoding) ENCODING1(name1, encoding) ENCODING1(name2, encoding)
-
- if (width >= 3) {
- switch (*start) {
- case 'A': case 'a':
- ENCODING1("ASCII", PM_ENCODING_US_ASCII);
- ENCODING1("ASCII-8BIT", PM_ENCODING_ASCII_8BIT);
- ENCODING1("ANSI_X3.4-1968", PM_ENCODING_US_ASCII);
- break;
- case 'B': case 'b':
- ENCODING1("BINARY", PM_ENCODING_ASCII_8BIT);
- ENCODING1("Big5", PM_ENCODING_BIG5);
- ENCODING2("Big5-HKSCS", "Big5-HKSCS:2008", PM_ENCODING_BIG5_HKSCS);
- ENCODING1("Big5-UAO", PM_ENCODING_BIG5_UAO);
- break;
- case 'C': case 'c':
- ENCODING1("CESU-8", PM_ENCODING_CESU_8);
- ENCODING1("CP437", PM_ENCODING_IBM437);
- ENCODING1("CP720", PM_ENCODING_IBM720);
- ENCODING1("CP737", PM_ENCODING_IBM737);
- ENCODING1("CP775", PM_ENCODING_IBM775);
- ENCODING1("CP850", PM_ENCODING_CP850);
- ENCODING1("CP852", PM_ENCODING_CP852);
- ENCODING1("CP855", PM_ENCODING_CP855);
- ENCODING1("CP857", PM_ENCODING_IBM857);
- ENCODING1("CP860", PM_ENCODING_IBM860);
- ENCODING1("CP861", PM_ENCODING_IBM861);
- ENCODING1("CP862", PM_ENCODING_IBM862);
- ENCODING1("CP864", PM_ENCODING_IBM864);
- ENCODING1("CP865", PM_ENCODING_IBM865);
- ENCODING1("CP866", PM_ENCODING_IBM866);
- ENCODING1("CP869", PM_ENCODING_IBM869);
- ENCODING1("CP874", PM_ENCODING_WINDOWS_874);
- ENCODING1("CP878", PM_ENCODING_KOI8_R);
- ENCODING1("CP863", PM_ENCODING_IBM863);
- ENCODING2("CP932", "csWindows31J", PM_ENCODING_WINDOWS_31J);
- ENCODING1("CP936", PM_ENCODING_GBK);
- ENCODING1("CP949", PM_ENCODING_CP949);
- ENCODING1("CP950", PM_ENCODING_CP950);
- ENCODING1("CP951", PM_ENCODING_CP951);
- ENCODING1("CP1250", PM_ENCODING_WINDOWS_1250);
- ENCODING1("CP1251", PM_ENCODING_WINDOWS_1251);
- ENCODING1("CP1252", PM_ENCODING_WINDOWS_1252);
- ENCODING1("CP1253", PM_ENCODING_WINDOWS_1253);
- ENCODING1("CP1254", PM_ENCODING_WINDOWS_1254);
- ENCODING1("CP1255", PM_ENCODING_WINDOWS_1255);
- ENCODING1("CP1256", PM_ENCODING_WINDOWS_1256);
- ENCODING1("CP1257", PM_ENCODING_WINDOWS_1257);
- ENCODING1("CP1258", PM_ENCODING_WINDOWS_1258);
- ENCODING1("CP51932", PM_ENCODING_CP51932);
- ENCODING1("CP65001", PM_ENCODING_UTF_8);
- break;
- case 'E': case 'e':
- ENCODING2("EUC-JP", "eucJP", PM_ENCODING_EUC_JP);
- ENCODING2("eucJP-ms", "euc-jp-ms", PM_ENCODING_EUC_JP_MS);
- ENCODING2("EUC-JIS-2004", "EUC-JISX0213", PM_ENCODING_EUC_JIS_2004);
- ENCODING2("EUC-KR", "eucKR", PM_ENCODING_EUC_KR);
- ENCODING2("EUC-CN", "eucCN", PM_ENCODING_GB2312);
- ENCODING2("EUC-TW", "eucTW", PM_ENCODING_EUC_TW);
- ENCODING1("Emacs-Mule", PM_ENCODING_EMACS_MULE);
- ENCODING1("external", PM_ENCODING_UTF_8);
- break;
- case 'F': case 'f':
- ENCODING1("filesystem", PM_ENCODING_UTF_8);
- break;
- case 'G': case 'g':
- ENCODING1("GBK", PM_ENCODING_GBK);
- ENCODING1("GB12345", PM_ENCODING_GB12345);
- ENCODING1("GB18030", PM_ENCODING_GB18030);
- ENCODING1("GB1988", PM_ENCODING_GB1988);
- ENCODING1("GB2312", PM_ENCODING_GB2312);
- break;
- case 'I': case 'i':
- ENCODING1("IBM437", PM_ENCODING_IBM437);
- ENCODING1("IBM720", PM_ENCODING_IBM720);
- ENCODING1("IBM737", PM_ENCODING_IBM737);
- ENCODING1("IBM775", PM_ENCODING_IBM775);
- ENCODING1("IBM850", PM_ENCODING_CP850);
- ENCODING1("IBM852", PM_ENCODING_IBM852);
- ENCODING1("IBM855", PM_ENCODING_IBM855);
- ENCODING1("IBM857", PM_ENCODING_IBM857);
- ENCODING1("IBM860", PM_ENCODING_IBM860);
- ENCODING1("IBM861", PM_ENCODING_IBM861);
- ENCODING1("IBM862", PM_ENCODING_IBM862);
- ENCODING1("IBM863", PM_ENCODING_IBM863);
- ENCODING1("IBM864", PM_ENCODING_IBM864);
- ENCODING1("IBM865", PM_ENCODING_IBM865);
- ENCODING1("IBM866", PM_ENCODING_IBM866);
- ENCODING1("IBM869", PM_ENCODING_IBM869);
- ENCODING2("ISO-8859-1", "ISO8859-1", PM_ENCODING_ISO_8859_1);
- ENCODING2("ISO-8859-2", "ISO8859-2", PM_ENCODING_ISO_8859_2);
- ENCODING2("ISO-8859-3", "ISO8859-3", PM_ENCODING_ISO_8859_3);
- ENCODING2("ISO-8859-4", "ISO8859-4", PM_ENCODING_ISO_8859_4);
- ENCODING2("ISO-8859-5", "ISO8859-5", PM_ENCODING_ISO_8859_5);
- ENCODING2("ISO-8859-6", "ISO8859-6", PM_ENCODING_ISO_8859_6);
- ENCODING2("ISO-8859-7", "ISO8859-7", PM_ENCODING_ISO_8859_7);
- ENCODING2("ISO-8859-8", "ISO8859-8", PM_ENCODING_ISO_8859_8);
- ENCODING2("ISO-8859-9", "ISO8859-9", PM_ENCODING_ISO_8859_9);
- ENCODING2("ISO-8859-10", "ISO8859-10", PM_ENCODING_ISO_8859_10);
- ENCODING2("ISO-8859-11", "ISO8859-11", PM_ENCODING_ISO_8859_11);
- ENCODING2("ISO-8859-13", "ISO8859-13", PM_ENCODING_ISO_8859_13);
- ENCODING2("ISO-8859-14", "ISO8859-14", PM_ENCODING_ISO_8859_14);
- ENCODING2("ISO-8859-15", "ISO8859-15", PM_ENCODING_ISO_8859_15);
- ENCODING2("ISO-8859-16", "ISO8859-16", PM_ENCODING_ISO_8859_16);
- break;
- case 'K': case 'k':
- ENCODING1("KOI8-R", PM_ENCODING_KOI8_R);
- ENCODING1("KOI8-U", PM_ENCODING_KOI8_U);
- break;
- case 'L': case 'l':
- ENCODING1("locale", PM_ENCODING_UTF_8);
- break;
- case 'M': case 'm':
- ENCODING1("macCentEuro", PM_ENCODING_MAC_CENT_EURO);
- ENCODING1("macCroatian", PM_ENCODING_MAC_CROATIAN);
- ENCODING1("macCyrillic", PM_ENCODING_MAC_CYRILLIC);
- ENCODING1("macGreek", PM_ENCODING_MAC_GREEK);
- ENCODING1("macIceland", PM_ENCODING_MAC_ICELAND);
- ENCODING1("MacJapanese", PM_ENCODING_MAC_JAPANESE);
- ENCODING1("MacJapan", PM_ENCODING_MAC_JAPANESE);
- ENCODING1("macRoman", PM_ENCODING_MAC_ROMAN);
- ENCODING1("macRomania", PM_ENCODING_MAC_ROMANIA);
- ENCODING1("macThai", PM_ENCODING_MAC_THAI);
- ENCODING1("macTurkish", PM_ENCODING_MAC_TURKISH);
- ENCODING1("macUkraine", PM_ENCODING_MAC_UKRAINE);
- break;
- case 'P': case 'p':
- ENCODING1("PCK", PM_ENCODING_WINDOWS_31J);
- break;
- case 'S': case 's':
- ENCODING1("Shift_JIS", PM_ENCODING_SHIFT_JIS);
- ENCODING1("SJIS", PM_ENCODING_WINDOWS_31J);
- ENCODING1("SJIS-DoCoMo", PM_ENCODING_SJIS_DOCOMO);
- ENCODING1("SJIS-KDDI", PM_ENCODING_SJIS_KDDI);
- ENCODING1("SJIS-SoftBank", PM_ENCODING_SJIS_SOFTBANK);
- ENCODING1("stateless-ISO-2022-JP", PM_ENCODING_STATELESS_ISO_2022_JP);
- ENCODING1("stateless-ISO-2022-JP-KDDI", PM_ENCODING_STATELESS_ISO_2022_JP_KDDI);
- break;
- case 'T': case 't':
- ENCODING1("TIS-620", PM_ENCODING_TIS_620);
- break;
- case 'U': case 'u':
- ENCODING1("US-ASCII", PM_ENCODING_US_ASCII);
- ENCODING2("UTF8-MAC", "UTF-8-HFS", PM_ENCODING_UTF8_MAC);
- ENCODING1("UTF8-DoCoMo", PM_ENCODING_UTF8_DOCOMO);
- ENCODING1("UTF8-KDDI", PM_ENCODING_UTF8_KDDI);
- ENCODING1("UTF8-SoftBank", PM_ENCODING_UTF8_SOFTBANK);
- break;
- case 'W': case 'w':
- ENCODING1("Windows-31J", PM_ENCODING_WINDOWS_31J);
- ENCODING1("Windows-874", PM_ENCODING_WINDOWS_874);
- ENCODING1("Windows-1250", PM_ENCODING_WINDOWS_1250);
- ENCODING1("Windows-1251", PM_ENCODING_WINDOWS_1251);
- ENCODING1("Windows-1252", PM_ENCODING_WINDOWS_1252);
- ENCODING1("Windows-1253", PM_ENCODING_WINDOWS_1253);
- ENCODING1("Windows-1254", PM_ENCODING_WINDOWS_1254);
- ENCODING1("Windows-1255", PM_ENCODING_WINDOWS_1255);
- ENCODING1("Windows-1256", PM_ENCODING_WINDOWS_1256);
- ENCODING1("Windows-1257", PM_ENCODING_WINDOWS_1257);
- ENCODING1("Windows-1258", PM_ENCODING_WINDOWS_1258);
- break;
- case '6':
- ENCODING1("646", PM_ENCODING_US_ASCII);
- break;
- }
- }
-
-#undef ENCODING2
-#undef ENCODING1
-
- // If we didn't match any encodings, return NULL.
- return NULL;
-}
diff --git a/prism/encoding.h b/prism/encoding.h
deleted file mode 100644
index 8fe01aea69..0000000000
--- a/prism/encoding.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/**
- * @file encoding.h
- *
- * The encoding interface and implementations used by the parser.
- */
-#ifndef PRISM_ENCODING_H
-#define PRISM_ENCODING_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_strncasecmp.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 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];
-
-/**
- * These are all of the encodings that prism supports.
- */
-typedef enum {
- PM_ENCODING_UTF_8 = 0,
- PM_ENCODING_ASCII_8BIT,
- PM_ENCODING_BIG5,
- PM_ENCODING_BIG5_HKSCS,
- PM_ENCODING_BIG5_UAO,
- PM_ENCODING_CESU_8,
- PM_ENCODING_CP51932,
- PM_ENCODING_CP850,
- PM_ENCODING_CP852,
- PM_ENCODING_CP855,
- PM_ENCODING_CP949,
- PM_ENCODING_CP950,
- PM_ENCODING_CP951,
- PM_ENCODING_EMACS_MULE,
- PM_ENCODING_EUC_JP,
- PM_ENCODING_EUC_JP_MS,
- PM_ENCODING_EUC_JIS_2004,
- PM_ENCODING_EUC_KR,
- PM_ENCODING_EUC_TW,
- PM_ENCODING_GB12345,
- PM_ENCODING_GB18030,
- PM_ENCODING_GB1988,
- PM_ENCODING_GB2312,
- PM_ENCODING_GBK,
- PM_ENCODING_IBM437,
- PM_ENCODING_IBM720,
- PM_ENCODING_IBM737,
- PM_ENCODING_IBM775,
- PM_ENCODING_IBM852,
- PM_ENCODING_IBM855,
- PM_ENCODING_IBM857,
- PM_ENCODING_IBM860,
- PM_ENCODING_IBM861,
- PM_ENCODING_IBM862,
- PM_ENCODING_IBM863,
- PM_ENCODING_IBM864,
- PM_ENCODING_IBM865,
- PM_ENCODING_IBM866,
- PM_ENCODING_IBM869,
- PM_ENCODING_ISO_8859_1,
- PM_ENCODING_ISO_8859_2,
- PM_ENCODING_ISO_8859_3,
- PM_ENCODING_ISO_8859_4,
- PM_ENCODING_ISO_8859_5,
- PM_ENCODING_ISO_8859_6,
- PM_ENCODING_ISO_8859_7,
- PM_ENCODING_ISO_8859_8,
- PM_ENCODING_ISO_8859_9,
- PM_ENCODING_ISO_8859_10,
- PM_ENCODING_ISO_8859_11,
- PM_ENCODING_ISO_8859_13,
- PM_ENCODING_ISO_8859_14,
- PM_ENCODING_ISO_8859_15,
- PM_ENCODING_ISO_8859_16,
- PM_ENCODING_KOI8_R,
- PM_ENCODING_KOI8_U,
- PM_ENCODING_MAC_CENT_EURO,
- PM_ENCODING_MAC_CROATIAN,
- PM_ENCODING_MAC_CYRILLIC,
- PM_ENCODING_MAC_GREEK,
- PM_ENCODING_MAC_ICELAND,
- PM_ENCODING_MAC_JAPANESE,
- PM_ENCODING_MAC_ROMAN,
- PM_ENCODING_MAC_ROMANIA,
- PM_ENCODING_MAC_THAI,
- PM_ENCODING_MAC_TURKISH,
- PM_ENCODING_MAC_UKRAINE,
- PM_ENCODING_SHIFT_JIS,
- PM_ENCODING_SJIS_DOCOMO,
- PM_ENCODING_SJIS_KDDI,
- PM_ENCODING_SJIS_SOFTBANK,
- PM_ENCODING_STATELESS_ISO_2022_JP,
- PM_ENCODING_STATELESS_ISO_2022_JP_KDDI,
- PM_ENCODING_TIS_620,
- PM_ENCODING_US_ASCII,
- PM_ENCODING_UTF8_MAC,
- PM_ENCODING_UTF8_DOCOMO,
- PM_ENCODING_UTF8_KDDI,
- PM_ENCODING_UTF8_SOFTBANK,
- PM_ENCODING_WINDOWS_1250,
- PM_ENCODING_WINDOWS_1251,
- PM_ENCODING_WINDOWS_1252,
- PM_ENCODING_WINDOWS_1253,
- PM_ENCODING_WINDOWS_1254,
- PM_ENCODING_WINDOWS_1255,
- PM_ENCODING_WINDOWS_1256,
- PM_ENCODING_WINDOWS_1257,
- PM_ENCODING_WINDOWS_1258,
- PM_ENCODING_WINDOWS_31J,
- PM_ENCODING_WINDOWS_874,
- PM_ENCODING_MAXIMUM
-} pm_encoding_type_t;
-
-/**
- * This is the table of all of the encodings that prism supports.
- */
-extern const pm_encoding_t pm_encodings[PM_ENCODING_MAXIMUM];
-
-/**
- * This is the default UTF-8 encoding. We need a reference to it to quickly
- * create parsers.
- */
-#define PM_ENCODING_UTF_8_ENTRY (&pm_encodings[PM_ENCODING_UTF_8])
-
-/**
- * This is the US-ASCII encoding. We need a reference to it to be able to
- * compare against it when a string is being created because it could possibly
- * need to fall back to ASCII-8BIT.
- */
-#define PM_ENCODING_US_ASCII_ENTRY (&pm_encodings[PM_ENCODING_US_ASCII])
-
-/**
- * Parse the given name of an encoding and return a pointer to the corresponding
- * encoding struct if one can be found, otherwise return NULL.
- *
- * @param start A pointer to the first byte of the name.
- * @param end A pointer to the last byte of the name.
- * @returns A pointer to the encoding struct if one is found, otherwise NULL.
- */
-const pm_encoding_t * pm_encoding_find(const uint8_t *start, const uint8_t *end);
-
-#endif
diff --git a/prism/extension.c b/prism/extension.c
deleted file mode 100644
index 6cf007b4df..0000000000
--- a/prism/extension.c
+++ /dev/null
@@ -1,1055 +0,0 @@
-#include "prism/extension.h"
-
-// NOTE: this file should contain only bindings. All non-trivial logic should be
-// in libprism 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_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, NUM2INT(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) {
- options->line = 1; // default
- 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->location.start - parser->start),
- LONG2FIX(comment->location.end - comment->location.start)
- };
-
- VALUE type = (comment->type == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
- 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 out the data location from the parser into a Location instance if one
- * exists.
- */
-static VALUE
-parser_data_loc(const pm_parser_t *parser, VALUE source) {
- if (parser->data_loc.end == NULL) {
- return Qnil;
- } else {
- VALUE argv[] = {
- source,
- LONG2FIX(parser->data_loc.start - parser->start),
- LONG2FIX(parser->data_loc.end - parser->data_loc.start)
- };
-
- return rb_class_new_instance(3, argv, rb_cPrismLocation);
- }
-}
-
-/**
- * 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->location.start - parser->start),
- LONG2FIX(error->location.end - error->location.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->location.start - parser->start),
- LONG2FIX(warning->location.end - warning->location.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_data_loc(&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(7, 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_data_loc(&parser, source),
- parser_errors(&parser, encoding, source),
- parser_warnings(&parser, encoding, source),
- source
- };
-
- VALUE result = rb_class_new_instance(7, 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;
-}
-
-/**
- * Parse the given input and return true if it parses without errors.
- */
-static VALUE
-parse_input_success_p(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);
- pm_node_destroy(&parser, node);
-
- VALUE result = parser.error_list.size == 0 ? Qtrue : Qfalse;
- pm_parser_free(&parser);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::parse_success?(source, **options) -> Array
- *
- * Parse the given string and return true if it parses without errors. For
- * supported options, see Prism::parse.
- */
-static VALUE
-parse_success_p(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_success_p(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::parse_file_success?(filepath, **options) -> Array
- *
- * Parse the given file and return true if it parses without errors. For
- * supported options, see Prism::parse.
- */
-static VALUE
-parse_file_success_p(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 result = parse_input_success_p(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return result;
-}
-
-/******************************************************************************/
-/* 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_ENTRY)) {
- 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_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);
- rb_define_singleton_method(rb_cPrism, "parse_success?", parse_success_p, -1);
- rb_define_singleton_method(rb_cPrism, "parse_file_success?", parse_file_success_p, -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 a21370cfa4..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.19.0"
-
-#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 85d04d6272..0000000000
--- a/prism/options.c
+++ /dev/null
@@ -1,189 +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, int32_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;
- }
-}
-
-/**
- * Read a 32-bit signed 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 int32_t
-pm_options_read_s32(const char *data) {
- if (((uintptr_t) data) % sizeof(int32_t) == 0) {
- return *((int32_t *) data);
- } else {
- int32_t value;
- memcpy(&value, data, sizeof(int32_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) {
- options->line = 1; // default
- if (data == NULL) return;
-
- 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_s32(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 8608838da8..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.
- */
- int32_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, int32_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 7f26054f09..0000000000
--- a/prism/parser.h
+++ /dev/null
@@ -1,716 +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/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>
-
-// TODO: remove this by renaming the original flag
-/**
- * Temporary alias for the PM_NODE_FLAG_STATIC_KEYS flag.
- */
-#define PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS PM_KEYWORD_HASH_NODE_FLAGS_STATIC_KEYS
-
-/**
- * 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,
-
- /** an ensure statement within a method definition */
- PM_CONTEXT_ENSURE_DEF,
-
- /** 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 else statement within a method definition */
- PM_CONTEXT_RESCUE_ELSE_DEF,
-
- /** a rescue statement */
- PM_CONTEXT_RESCUE,
-
- /** a rescue statement within a method definition */
- PM_CONTEXT_RESCUE_DEF,
-
- /** 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_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;
-
- /** The location of the comment in the source. */
- pm_location_t location;
-
- /** 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 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;
-
- /**
- * An integer indicating the number of numbered parameters on this scope.
- * This is necessary to determine if child blocks are allowed to use
- * numbered parameters, and to pass information to consumers of the AST
- * about how many numbered parameters exist.
- */
- uint8_t numbered_parameters;
-} 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 optional location of the __END__ keyword and its contents. */
- pm_location_t data_loc;
-
- /** 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.
- */
- const 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;
-
- /**
- * 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.
- */
- int32_t start_line;
-
- /**
- * When a string-like expression is being lexed, any byte or escape sequence
- * that resolves to a value whose top bit is set (i.e., >= 0x80) will
- * explicitly set the encoding to the same encoding as the source.
- * Alternatively, if a unicode escape sequence is used (e.g., \\u{80}) that
- * resolves to a value whose top bit is set, then the encoding will be
- * explicitly set to UTF-8.
- *
- * The _next_ time this happens, if the encoding that is about to become the
- * explicitly set encoding does not match the previously set explicit
- * encoding, a mixed encoding error will be emitted.
- *
- * When the expression is finished being lexed, the explicit encoding
- * controls the encoding of the expression. For the most part this means
- * that the expression will either be encoded in the source encoding or
- * UTF-8. This holds for all encodings except US-ASCII. If the source is
- * US-ASCII and an explicit encoding was set that was _not_ UTF-8, then the
- * expression will be encoded as ASCII-8BIT.
- *
- * Note that if the expression is a list, different elements within the same
- * list can have different encodings, so this will get reset between each
- * element. Furthermore all of this only applies to lists that support
- * interpolation, because otherwise escapes that could change the encoding
- * are ignored.
- *
- * At first glance, it may make more sense for this to live on the lexer
- * mode, but we need it here to communicate back to the parser for character
- * literals that do not push a new lexer mode.
- */
- const pm_encoding_t *explicit_encoding;
-
- /** 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;
-
- /** The current parameter name id on parsing its default value. */
- pm_constant_id_t current_param_name;
-
- /**
- * 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 b897d9cdd7..0000000000
--- a/prism/prism.c
+++ /dev/null
@@ -1,17487 +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 with 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_ENSURE_DEF: return "ENSURE_DEF";
- 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_RESCUE_ELSE_DEF: return "RESCUE_ELSE_DEF";
- case PM_CONTEXT_RESCUE_DEF: return "RESCUE_DEF";
- 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;
- }
-
- parser->explicit_encoding = NULL;
- return lex_mode_push(parser, lex_mode);
-}
-
-/**
- * Push on a new list lex mode that is only used for compatibility. This is
- * called when we're at the end of the file. We want the parser to be able to
- * perform its normal error tolerance.
- */
-static inline bool
-lex_mode_push_list_eof(pm_parser_t *parser) {
- return lex_mode_push_list(parser, false, '\0');
-}
-
-/**
- * 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;
- }
-
- parser->explicit_encoding = NULL;
- return lex_mode_push(parser, lex_mode);
-}
-
-/**
- * Push on a new string lex mode that is only used for compatibility. This is
- * called when we're at the end of the file. We want the parser to be able to
- * perform its normal error tolerance.
- */
-static inline bool
-lex_mode_push_string_eof(pm_parser_t *parser) {
- return lex_mode_push_string(parser, false, false, '\0', '\0');
-}
-
-/**
- * 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)) == (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 a format string.
- */
-#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
-
-/**
- * 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
- * using a format string.
- */
-#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, (location)->start, (location)->end, diag_id, __VA_ARGS__)
-
-/**
- * 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
- * given node and a format string.
- */
-#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, node->location.start, node->location.end, diag_id, __VA_ARGS__)
-
-/**
- * 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 an error to the list of errors on the parser using the location of the
- * given token and a format string.
- */
-#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, (token).start, (token).end, diag_id, __VA_ARGS__)
-
-/**
- * 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);
-}
-
-/**
- * Check whether or not the given node is value expression.
- * If the node is value node, it returns NULL.
- * If not, it returns the pointer to the node to be inspected as "void expression".
- */
-static pm_node_t*
-pm_check_value_expression(pm_node_t *node) {
- pm_node_t* void_node = NULL;
-
- while (node != NULL) {
- switch (PM_NODE_TYPE(node)) {
- case PM_RETURN_NODE:
- case PM_BREAK_NODE:
- case PM_NEXT_NODE:
- case PM_REDO_NODE:
- case PM_RETRY_NODE:
- case PM_MATCH_REQUIRED_NODE:
- return void_node != NULL ? void_node : node;
- case PM_MATCH_PREDICATE_NODE:
- return NULL;
- case PM_BEGIN_NODE: {
- pm_begin_node_t *cast = (pm_begin_node_t *) node;
- node = (pm_node_t *) cast->statements;
- break;
- }
- case PM_PARENTHESES_NODE: {
- pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
- node = (pm_node_t *) cast->body;
- break;
- }
- case PM_STATEMENTS_NODE: {
- pm_statements_node_t *cast = (pm_statements_node_t *) node;
- node = cast->body.nodes[cast->body.size - 1];
- break;
- }
- case PM_IF_NODE: {
- pm_if_node_t *cast = (pm_if_node_t *) node;
- if (cast->statements == NULL || cast->consequent == NULL) {
- return NULL;
- }
- pm_node_t *vn = pm_check_value_expression((pm_node_t *) cast->statements);
- if (vn == NULL) {
- return NULL;
- }
- if (void_node == NULL) {
- void_node = vn;
- }
- node = cast->consequent;
- break;
- }
- case PM_UNLESS_NODE: {
- pm_unless_node_t *cast = (pm_unless_node_t *) node;
- if (cast->statements == NULL || cast->consequent == NULL) {
- return NULL;
- }
- pm_node_t *vn = pm_check_value_expression((pm_node_t *) cast->statements);
- if (vn == NULL) {
- return NULL;
- }
- if (void_node == NULL) {
- void_node = vn;
- }
- node = (pm_node_t *) cast->consequent;
- break;
- }
- case PM_ELSE_NODE: {
- pm_else_node_t *cast = (pm_else_node_t *) node;
- node = (pm_node_t *) cast->statements;
- break;
- }
- case PM_AND_NODE: {
- pm_and_node_t *cast = (pm_and_node_t *) node;
- node = cast->left;
- break;
- }
- case PM_OR_NODE: {
- pm_or_node_t *cast = (pm_or_node_t *) node;
- node = cast->left;
- break;
- }
- default:
- return NULL;
- }
- }
-
- return NULL;
-}
-
-static inline void
-pm_assert_value_expression(pm_parser_t *parser, pm_node_t *node) {
- pm_node_t *void_node = pm_check_value_expression(node);
- if (void_node != NULL) {
- pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
- }
-}
-
-/**
- * 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(parser);
- */
-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;
-
-/**
- * Retrieve the end location of a `pm_arguments_t` object.
- */
-static inline const uint8_t *
-pm_arguments_end(pm_arguments_t *arguments) {
- if (arguments->block != NULL) {
- const uint8_t *end = arguments->block->location.end;
- if (arguments->closing_loc.start != NULL && arguments->closing_loc.end > end) {
- end = arguments->closing_loc.end;
- }
- return end;
- }
- if (arguments->closing_loc.start != NULL) {
- return arguments->closing_loc.end;
- }
- if (arguments->arguments != NULL) {
- return arguments->arguments->base.location.end;
- }
- return arguments->closing_loc.end;
-}
-
-/**
- * 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 flag handling functions */
-/******************************************************************************/
-
-/**
- * Set the given flag on the given node.
- */
-static inline void
-pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
- node->flags |= flag;
-}
-
-/**
- * Remove the given flag from the given node.
- */
-static inline void
-pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
- node->flags &= (pm_node_flags_t) ~flag;
-}
-
-
-/******************************************************************************/
-/* 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_assert_value_expression(parser, left);
-
- 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) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) {
- pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
- pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
- }
-}
-
-/**
- * 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) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_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, uint32_t locals_body_index, const pm_token_t *opening, pm_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,
- .locals_body_index = locals_body_index,
- .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_assert_value_expression(parser, receiver);
-
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = receiver->location.start;
- node->base.location.end = pm_arguments_end(arguments);
-
- 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_assert_value_expression(parser, receiver);
- pm_assert_value_expression(parser, 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_assert_value_expression(parser, receiver);
-
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = receiver->location.start;
- const uint8_t *end = pm_arguments_end(arguments);
- if (end == NULL) {
- end = message->end;
- }
- node->base.location.end = 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) {
- pm_node_flag_set((pm_node_t *)node, 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;
- node->base.location.end = pm_arguments_end(arguments);
-
- 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_assert_value_expression(parser, receiver);
-
- 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_assert_value_expression(parser, receiver);
-
- pm_call_node_t *node = pm_call_node_create(parser);
-
- node->base.location.start = receiver->location.start;
- node->base.location.end = pm_arguments_end(arguments);
-
- 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) {
- pm_node_flag_set((pm_node_t *)node, 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_assert_value_expression(parser, receiver);
-
- 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 PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_VARIABLE_CALL);
-}
-
-/**
- * Returns whether or not this call is to the [] method in the index form without a block (as
- * opposed to `foo.[]` and `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] == ']') &&
- (node->block == NULL || PM_NODE_TYPE_P(node->block, PM_BLOCK_ARGUMENT_NODE))
- );
-}
-
-/**
- * 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 CallTargetNode node from an existing call
- * node.
- */
-static pm_call_target_node_t *
-pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
- pm_call_target_node_t *node = PM_ALLOC_NODE(parser, pm_call_target_node_t);
-
- *node = (pm_call_target_node_t) {
- {
- .type = PM_CALL_TARGET_NODE,
- .flags = target->base.flags,
- .location = target->base.location
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .name = target->name,
- .message_loc = target->message_loc
- };
-
- // 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 IndexTargetNode node from an existing call
- * node.
- */
-static pm_index_target_node_t *
-pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
- pm_index_target_node_t *node = PM_ALLOC_NODE(parser, pm_index_target_node_t);
-
- *node = (pm_index_target_node_t) {
- {
- .type = PM_INDEX_TARGET_NODE,
- .flags = target->base.flags,
- .location = target->base.location
- },
- .receiver = target->receiver,
- .opening_loc = target->opening_loc,
- .arguments = target->arguments,
- .closing_loc = target->closing_loc,
- .block = target->block
- };
-
- // 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, 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 = NULL,
- .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_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 and initialize a new CaseMatchNode node.
- */
-static pm_case_match_node_t *
-pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
- pm_case_match_node_t *node = PM_ALLOC_NODE(parser, pm_case_match_node_t);
-
- *node = (pm_case_match_node_t) {
- {
- .type = PM_CASE_MATCH_NODE,
- .location = {
- .start = case_keyword->start,
- .end = end_keyword->end
- },
- },
- .predicate = predicate,
- .consequent = NULL,
- .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 CaseMatchNode node.
- */
-static void
-pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
- assert(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 CaseMatchNode node.
- */
-static void
-pm_case_match_node_consequent_set(pm_case_match_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 CaseMatchNode node.
- */
-static void
-pm_case_match_node_end_keyword_loc_set(pm_case_match_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_assert_value_expression(parser, parent);
-
- 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,
- uint32_t locals_body_index,
- 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,
- .locals_body_index = locals_body_index,
- .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);
-
- bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
- if (static_literal) {
- pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
- static_literal = !PM_NODE_TYPE_P(assoc->key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_HASH_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_RANGE_NODE);
- static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
- static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- if (!static_literal) {
- pm_node_flag_unset((pm_node_t *)hash, 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,
- const pm_token_t *then_keyword,
- 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,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
- .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,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .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, const pm_token_t *qmark, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
- pm_assert_value_expression(parser, predicate);
- 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,
- .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
- .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 ImplicitRestNode node.
- */
-static pm_implicit_rest_node_t *
-pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_COMMA);
-
- pm_implicit_rest_node_t *node = PM_ALLOC_NODE(parser, pm_implicit_rest_node_t);
-
- *node = (pm_implicit_rest_node_t) {
- {
- .type = PM_IMPLICIT_REST_NODE,
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }
- };
-
- 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;
- pm_node_flag_set((pm_node_t *)node, 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,
- .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS
- },
- .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) {
- // If the element being added is not an AssocNode or does not have a symbol key, then
- // we want to turn the STATIC_KEYS flag off.
- // TODO: Rename the flag to SYMBOL_KEYS instead.
- if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
- pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
- }
-
- 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,
- uint32_t locals_body_index,
- const pm_token_t *operator,
- const pm_token_t *opening,
- const pm_token_t *closing,
- pm_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,
- .locals_body_index = locals_body_index,
- .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_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
-
- if (parser->current_param_name == name_id) {
- pm_parser_err_token(parser, name, PM_ERR_PARAMETER_CIRCULAR);
- }
-
- 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 = name_id,
- .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;
-}
-
-/**
- * Returns true if the given bounds comprise a numbered parameter (i.e., they
- * are of the form /^_\d$/).
- */
-static inline bool
-pm_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]));
-}
-
-/**
- * Ensure the given bounds do not comprise a numbered parameter. If they do, add
- * an appropriate error message to the parser.
- */
-static inline void
-pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- if (pm_token_is_numbered_parameter(start, end)) {
- PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
- }
-}
-
-/**
- * Allocate and initialize a new LocalVariableTargetNode node with the given
- * name and depth.
- */
-static pm_local_variable_target_node_t *
-pm_local_variable_target_node_create_values(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
- pm_local_variable_target_node_t *node = PM_ALLOC_NODE(parser, pm_local_variable_target_node_t);
-
- *node = (pm_local_variable_target_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_TARGET_NODE,
- .location = *location
- },
- .name = name,
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * 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_refute_numbered_parameter(parser, name->start, name->end);
-
- return pm_local_variable_target_node_create_values(
- parser,
- &(pm_location_t) { .start = name->start, .end = name->end },
- pm_parser_constant_id_token(parser, name),
- 0
- );
-}
-
-/**
- * Allocate and initialize a new LocalVariableTargetNode node with the given depth.
- */
-static pm_local_variable_target_node_t *
-pm_local_variable_target_node_create_depth(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
- pm_refute_numbered_parameter(parser, name->start, name->end);
-
- return pm_local_variable_target_node_create_values(
- parser,
- &(pm_location_t) { .start = name->start, .end = name->end },
- pm_parser_constant_id_token(parser, name),
- depth
- );
-}
-
-/**
- * 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_assert_value_expression(parser, value);
-
- 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_assert_value_expression(parser, value);
-
- 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,
- .targets = { 0 }
- };
-
- 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) || PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_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 and initialize a new NumberedParametersNode node.
- */
-static pm_numbered_parameters_node_t *
-pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
- pm_numbered_parameters_node_t *node = PM_ALLOC_NODE(parser, pm_numbered_parameters_node_t);
-
- *node = (pm_numbered_parameters_node_t) {
- {
- .type = PM_NUMBERED_PARAMETERS_NODE,
- .location = *location
- },
- .maximum = maximum
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize 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_assert_value_expression(parser, left);
-
- 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_node_t *param) {
- pm_parameters_node_location_set(params, 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_assert_value_expression(parser, left);
- pm_assert_value_expression(parser, 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.
- pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
-}
-
-/**
- * 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 = pm_arguments_end(arguments);
- if (end == NULL) {
- assert(false && "unreachable");
- }
-
- *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, const pm_token_t *then_keyword, 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,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
- .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,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .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,
- .flags = PM_STRING_FLAGS_FROZEN,
- .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_parameters = 0,
- };
-
- pm_constant_id_list_init(&scope->locals);
- parser->current_scope = scope;
-
- return true;
-}
-
-/**
- * Check if any of the currently visible scopes contain a local variable
- * described by the given constant id.
- */
-static int
-pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
- pm_scope_t *scope = parser->current_scope;
- int depth = 0;
-
- while (scope != NULL) {
- if (pm_constant_id_list_includes(&scope->locals, constant_id)) return depth;
- if (scope->closed) break;
-
- scope = scope->previous;
- depth++;
- }
-
- return -1;
-}
-
-/**
- * Check if any of the currently visible scopes contain a local variable
- * described by the given token. This function implicitly inserts a constant
- * into the constant pool.
- */
-static inline int
-pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
- return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
-}
-
-/**
- * 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) {
- if (!pm_constant_id_list_includes(&parser->current_scope->locals, constant_id)) {
- pm_constant_id_list_append(&parser->current_scope->locals, constant_id);
- }
-}
-
-/**
- * Set the numbered_parameters value of the current scope.
- */
-static inline void
-pm_parser_numbered_parameters_set(pm_parser_t *parser, uint8_t numbered_parameters) {
- parser->current_scope->numbered_parameters = numbered_parameters;
-}
-
-/**
- * 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.
- pm_refute_numbered_parameter(parser, name->start, name->end);
-
- // We want to ignore any parameter name that starts with an underscore.
- if ((name->start < name->end) && (*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) {
- size_t width;
- if ((width = parser->encoding->alpha_char(b, parser->end - b)) != 0) {
- return width;
- } else if (*b == '_') {
- return 1;
- } else if (*b >= 0x80) {
- return parser->encoding->char_width(b, parser->end - b);
- } else {
- return 0;
- }
- } 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);
- }
-}
-
-/**
- * Similar to char_is_identifier but this function assumes that the encoding
- * has not been changed.
- */
-static inline size_t
-char_is_identifier_utf8(const uint8_t *b, const uint8_t *end) {
- if (*b < 0x80) {
- return (*b == '_') || (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT ? 1 : 0);
- } else {
- return (size_t) (pm_encoding_utf_8_alnum_char(b, 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) {
- size_t width;
- if ((width = parser->encoding->alnum_char(b, parser->end - b)) != 0) {
- return width;
- } else if (*b == '_') {
- return 1;
- } else if (*b >= 0x80) {
- return parser->encoding->char_width(b, parser->end - b);
- } else {
- return 0;
- }
- }
- return char_is_identifier_utf8(b, parser->end);
-}
-
-// 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) {
- const pm_encoding_t *encoding = pm_encoding_find(start, end);
-
- if (encoding != NULL) {
- if (encoding != PM_ENCODING_UTF_8_ENTRY) {
- parser->encoding = encoding;
- parser->encoding_changed = true;
- if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
- }
-
- return true;
- }
-
- 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) {
- bool result = true;
-
- 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)
- ) {
- result = 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 result;
-}
-
-/******************************************************************************/
-/* 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:
- case PM_CONTEXT_ENSURE_DEF:
- 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:
- case PM_CONTEXT_RESCUE_DEF:
- 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:
- case PM_CONTEXT_RESCUE_ELSE_DEF:
- 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:
- case PM_CONTEXT_DEF_PARAMS:
- case PM_CONTEXT_ENSURE_DEF:
- case PM_CONTEXT_RESCUE_DEF:
- case PM_CONTEXT_RESCUE_ELSE_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, bool* seen_e) {
- 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, '-'));
- *seen_e = true;
-
- if (pm_char_is_decimal_digit(peek(parser))) {
- 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, bool* seen_e) {
- pm_token_type_t type = PM_TOKEN_INTEGER;
- *seen_e = false;
-
- 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, seen_e);
- break;
- }
-
- // 0exxx is a float
- case 'e':
- case 'E': {
- type = lex_optional_float_suffix(parser, seen_e);
- 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, seen_e);
- }
-
- 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) {
- bool seen_e = false;
- type = lex_numeric_prefix(parser, &seen_e);
-
- 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 (!seen_e && 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 the token type. Otherwise, it returns PM_TOKEN_EOF. The arguments are as follows:
- *
- * * `parser` - the parser object
- * * `current_start` - pointer to the start of the current token
- * * `value` - the literal string that we're checking for
- * * `vlen` - the length of the token
- * * `state` - the state that we should transition to if the token matches
- * * `type` - the expected token type
- * * `modifier_type` - the expected modifier token type
- */
-static inline pm_token_type_t
-lex_keyword(pm_parser_t *parser, const uint8_t *current_start, const char *value, size_t vlen, pm_lex_state_t state, pm_token_type_t type, pm_token_type_t modifier_type) {
- if (memcmp(current_start, value, vlen) == 0) {
- pm_lex_state_t last_state = parser->lex_state;
-
- 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;
- bool encoding_changed = parser->encoding_changed;
-
- if (encoding_changed) {
- while (current_end < end && (width = char_is_identifier(parser, current_end)) > 0) {
- current_end += width;
- }
- } else {
- while (current_end < end && (width = char_is_identifier_utf8(current_end, 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, current_start, "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, current_start, "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, current_start, "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, current_start, "in", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "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, current_start, "and", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_AND, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "def", width, PM_LEX_STATE_FNAME, PM_TOKEN_KEYWORD_DEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "end", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "END", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "for", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_FOR, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "nil", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_NIL, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "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, current_start, "case", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_CASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "else", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "next", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_NEXT, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "redo", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_REDO, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "self", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_SELF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "then", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "true", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_TRUE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "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, current_start, "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, current_start, "begin", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_BEGIN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "BEGIN", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_BEGIN_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "break", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_BREAK, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "class", width, PM_LEX_STATE_CLASS, PM_TOKEN_KEYWORD_CLASS, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "elsif", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "false", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_FALSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "retry", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_RETRY, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "super", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_SUPER, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "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, current_start, "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, current_start, "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, current_start, "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, current_start, "ensure", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "module", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_MODULE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "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, current_start, "return", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RETURN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "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, current_start, "__LINE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___LINE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "__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, current_start, "__ENCODING__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___ENCODING__, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- }
- }
-
- if (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 flags, const uint8_t *start, const uint8_t *end, uint32_t value) {
- // \u escape sequences in string-like structures implicitly change the
- // encoding to UTF-8 if they are >= 0x80 or if they are used in a character
- // literal.
- if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
- if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) {
- PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
- }
-
- parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
- }
-
- 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);
- }
-}
-
-/**
- * When you're writing a byte to the unescape buffer, if the byte is non-ASCII
- * (i.e., the top bit is set) then it locks in the encoding.
- */
-static inline void
-escape_write_byte_encoded(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t byte) {
- if (byte >= 0x80) {
- if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
- }
-
- parser->explicit_encoding = parser->encoding;
- }
-
- pm_buffer_append_byte(buffer, byte);
-}
-
-/**
- * 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_parser_t *parser, 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 {
- escape_write_byte_encoded(parser, 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++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\\', flags));
- return;
- }
- case '\'': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\'', flags));
- return;
- }
- case 'a': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\a', flags));
- return;
- }
- case 'b': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\b', flags));
- return;
- }
- case 'e': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\033', flags));
- return;
- }
- case 'f': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\f', flags));
- return;
- }
- case 'n': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\n', flags));
- return;
- }
- case 'r': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\r', flags));
- return;
- }
- case 's': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte(' ', flags));
- return;
- }
- case 't': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\t', flags));
- return;
- }
- case 'v': {
- parser->current.end++;
- escape_write_byte_encoded(parser, buffer, escape_byte('\v', flags));
- 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++;
- }
- }
-
- escape_write_byte_encoded(parser, 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 {
- escape_write_byte_encoded(parser, 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, flags, 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, flags, 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(parser, 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(parser, 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(parser, 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(parser, 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(parser, buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
- return;
- }
- case '\r': {
- if (peek_offset(parser, 1) == '\n') {
- parser->current.end += 2;
- escape_write_byte_encoded(parser, buffer, escape_byte('\n', flags));
- return;
- }
- }
- /* fallthrough */
- default: {
- if (parser->current.end < parser->end) {
- escape_write_byte_encoded(parser, 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 here.
- 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,
- .location = { parser->current.start, 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->location.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->location.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
- }
-
- parser->explicit_encoding = NULL;
- 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++);
- } else {
- lex_mode_push_list_eof(parser);
- }
-
- 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++);
- } else {
- lex_mode_push_list_eof(parser);
- }
-
- 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++;
- } else {
- lex_mode_push_regexp(parser, '\0', '\0');
- }
-
- 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++;
- } else {
- lex_mode_push_string_eof(parser);
- }
-
- 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++;
- } else {
- lex_mode_push_string_eof(parser);
- }
-
- 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++;
- } else {
- lex_mode_push_string_eof(parser);
- }
-
- 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++);
- } else {
- lex_mode_push_list_eof(parser);
- }
-
- 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++);
- } else {
- lex_mode_push_list_eof(parser);
- }
-
- 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++;
- } else {
- lex_mode_push_string_eof(parser);
- }
-
- 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);
-
- parser->data_loc.start = parser->current.start;
- parser->data_loc.end = parser->current.end;
-
- 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) ||
- pm_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.
- parser->current.end = parser->end;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- 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') {
- if (lex_mode->as.regexp.terminator != '\r') {
- 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) {
- // Some characters when they are used as the
- // terminator also receive an escape. They are
- // enumerated here.
- switch (peeked) {
- case '$': case ')': case '*': case '+':
- case '.': case '>': case '?': case ']':
- case '^': case '|': case '}':
- pm_token_buffer_push(&token_buffer, '\\');
- break;
- default:
- break;
- }
-
- 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.
- parser->current.end = parser->end;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- 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 a string content token.
- parser->current.end = parser->end;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- 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;
- if (start + ident_length <= parser->end) {
- const uint8_t *newline = next_newline(start, parser->end - start);
- const uint8_t *ident_end = newline;
- const uint8_t *terminator_end = newline;
-
- if (newline == NULL) {
- terminator_end = parser->end;
- ident_end = parser->end;
- } else {
- terminator_end++;
- if (newline[-1] == '\r') {
- ident_end--; // Remove \r
- }
- }
-
- const uint8_t *terminator_start = ident_end - ident_length;
- const uint8_t *cursor = start;
-
- if (
- lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_DASH ||
- lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_TILDE
- ) {
- while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
- cursor++;
- }
- }
-
- if (
- (cursor == terminator_start) &&
- (memcmp(terminator_start, ident_start, ident_length) == 0)
- ) {
- if (newline != NULL) {
- pm_newline_list_append(&parser->newline_list, newline);
- }
-
- parser->current.end = terminator_end;
- 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_state_set(parser, PM_LEX_STATE_END);
- LEX(PM_TOKEN_HEREDOC_END);
- }
- }
-
- size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.indent);
- 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;
-
- if (!was_escaped_newline && (start + ident_length <= parser->end)) {
- // We want to match the terminator starting from the end of the line in case
- // there is whitespace in the ident such as <<-' DOC' or <<~' DOC'.
- const uint8_t *newline = next_newline(start, parser->end - start);
-
- if (newline == NULL) {
- newline = parser->end;
- } else if (newline[-1] == '\r') {
- newline--; // Remove \r
- }
-
- // Start of a possible terminator.
- const uint8_t *terminator_start = newline - ident_length;
-
- // Cursor to check for the leading whitespace. We skip the
- // leading whitespace if we have a - or ~ heredoc.
- const uint8_t *cursor = start;
-
- if (lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_DASH ||
- lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_TILDE) {
- while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
- cursor++;
- }
- }
-
- if (
- cursor == terminator_start &&
- (memcmp(terminator_start, ident_start, ident_length) == 0)
- ) {
- parser->current.end = breakpoint + 1;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- }
-
- 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 (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 a string content token.
- parser->current.end = parser->end;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- }
-
- 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
- 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, // => in
- PM_BINDING_POWER_DEFINED = 14, // defined?
- PM_BINDING_POWER_MULTI_ASSIGNMENT = 16, // =
- PM_BINDING_POWER_ASSIGNMENT = 18, // = += -= *= /= %= &= |= ^= &&= ||= <<= >>= **=
- PM_BINDING_POWER_TERNARY = 20, // ?:
- PM_BINDING_POWER_RANGE = 22, // .. ...
- PM_BINDING_POWER_LOGICAL_OR = 24, // ||
- PM_BINDING_POWER_LOGICAL_AND = 26, // &&
- PM_BINDING_POWER_EQUALITY = 28, // <=> == === != =~ !~
- PM_BINDING_POWER_COMPARISON = 30, // > >= < <=
- PM_BINDING_POWER_BITWISE_OR = 32, // | ^
- PM_BINDING_POWER_BITWISE_AND = 34, // &
- PM_BINDING_POWER_SHIFT = 36, // << >>
- PM_BINDING_POWER_TERM = 38, // + -
- PM_BINDING_POWER_FACTOR = 40, // * / %
- PM_BINDING_POWER_UMINUS = 42, // -@
- PM_BINDING_POWER_EXPONENT = 44, // **
- PM_BINDING_POWER_UNARY = 46, // ! ~ +@
- PM_BINDING_POWER_INDEX = 48, // [] []=
- PM_BINDING_POWER_CALL = 50, // :: .
- PM_BINDING_POWER_MAX = 52
-} 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;
-
- /**
- * Whether or not this token can be used as non-associative binary operator.
- * Non-associative operators (e.g. in and =>) need special treatment in parse_expression.
- */
- bool nonassoc;
-} pm_binding_powers_t;
-
-#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
-#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
-#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
-#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
-#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
-
-pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = {
- // if unless until while
- [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),
-
- // rescue
- [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER_RESCUE),
-
- // and or
- [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
- [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
-
- // => in
- [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
- [PM_TOKEN_KEYWORD_IN] = NON_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] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
- [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
- [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
- [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
-
- // ||
- [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] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_LESS_EQUAL_GREATER] = NON_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, 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 four given types.
- */
-static inline bool
-match4(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) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
-}
-
-/**
- * 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, bool accepts_command_call, pm_diagnostic_id_t diag_id);
-
-/**
- * This is a wrapper of parse_expression, which also checks whether the resulting node is value expression.
- */
-static pm_node_t *
-parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
- pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, diag_id);
- pm_assert_value_expression(parser, node);
- return node;
-}
-
-/**
- * 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, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
- if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, binding_power, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR);
- return (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
- }
-
- return parse_value_expression(parser, binding_power, accepts_command_call, 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.
- // This silences clang analyzer warning about leak of memory pointed by `name`.
- // NOLINTNEXTLINE(clang-analyzer-*)
- *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 (pm_token_is_numbered_parameter(target->location.start, target->location.end)) {
- PM_PARSER_ERR_NODE_FORMAT(parser, target, PM_ERR_PARAMETER_NUMBERED_RESERVED, target->location.start);
- } 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;
- 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;
-
- pm_refute_numbered_parameter(parser, message.start, message.end);
- 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 *) pm_call_target_node_create(parser, 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 (pm_call_node_index_p(call)) {
- return (pm_node_t *) pm_index_target_node_create(parser, call);
- }
- }
- /* 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 one of an =, an 'in' in for indexes, and a ')' in parens after the targets.
- if (
- !match1(parser, PM_TOKEN_EQUAL) &&
- !(context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) &&
- !(context_p(parser, PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
- ) {
- 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:
- pm_node_destroy(parser, value);
- 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);
- if (context_def_p(parser)) {
- pm_parser_err_node(parser, (pm_node_t *) node, PM_ERR_WRITE_TARGET_IN_METHOD);
- }
- 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: {
- pm_refute_numbered_parameter(parser, target->location.start, target->location.end);
- 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);
-
- pm_refute_numbered_parameter(parser, message.start, message.end);
- 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);
- pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE);
- 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 (pm_call_node_index_p(call)) {
- 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);
- pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE);
- 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_rest = 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_rest) {
- 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, false, 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_rest = true;
- } else if (token_begins_expression_p(parser->current.type)) {
- pm_node_t *target = parse_expression(parser, binding_power, false, 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'll set the implicit rest flag to indicate this.
- pm_node_t *rest = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
- pm_multi_target_node_targets_append(parser, result, rest);
- 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, true, 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. returns 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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_first_argument = false;
- bool parsed_bare_hash = false;
- bool parsed_block_argument = false;
- bool parsed_forwarding_arguments = false;
-
- while (!match1(parser, PM_TOKEN_EOF)) {
- if (parsed_block_argument) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
- }
- if (parsed_forwarding_arguments) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
- }
-
- 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 = parse_assocs(parser, (pm_node_t *) hash);
- parsed_bare_hash = true;
- parse_arguments_append(parser, arguments, argument);
- if (contains_keyword_splat) {
- pm_node_flag_set((pm_node_t *)arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_EXPECT_ARGUMENT);
- } else {
- if (pm_parser_local_depth(parser, &operator) == -1) {
- // A block forwarding in a method having `...` parameter (e.g. `def foo(...); bar(&); end`) is available.
- pm_constant_id_t ellipsis_id = pm_parser_constant_id_constant(parser, "...", 3);
- if (pm_parser_local_depth_constant_id(parser, ellipsis_id) == -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 (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
- 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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, false, 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);
- }
- if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
- }
-
- argument = (pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->previous);
- parse_arguments_append(parser, arguments, argument);
- parsed_forwarding_arguments = true;
- break;
- }
- }
- }
- /* fallthrough */
- default: {
- if (argument == NULL) {
- argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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) {
- pm_node_flag_set((pm_node_t *)arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT);
- }
- break;
- }
- }
-
- parsed_first_argument = true;
-
- // 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, which isn't allowed in
- // the grammar. In other places, multi targets _do_ allow trailing
- // commas, so here we'll assume this is a mistake of the user not
- // knowing it's not allowed here.
- if (node->lefts.size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- param = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
- pm_multi_target_node_targets_append(parser, node, param);
- pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
- 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_constant_id_t old_param_name = parser->current_param_name;
- parser->current_param_name = pm_parser_constant_id_token(parser, &name);
- pm_node_t *value = parse_value_expression(parser, binding_power, false, 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);
-
- parser->current_param_name = old_param_name;
- 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_constant_id_t old_param_name = parser->current_param_name;
- parser->current_param_name = pm_parser_constant_id_token(parser, &local);
- pm_node_t *value = parse_value_expression(parser, binding_power, false, PM_ERR_PARAMETER_NO_DEFAULT_KW);
- parser->current_param_name = old_param_name;
- 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_node_t *param = (pm_node_t *) 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, param, PM_ERR_PARAMETER_SPLAT_MULTI);
- pm_parameters_node_posts_append(params, 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.
- pm_node_t *param = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
-
- 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, bool def_p) {
- 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, false, 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, false, 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, false, 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, def_p ? PM_CONTEXT_RESCUE_DEF : 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, def_p ? PM_CONTEXT_RESCUE_ELSE_DEF : 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, def_p ? PM_CONTEXT_ENSURE_DEF : 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, bool def_p) {
- 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, def_p);
-
- // 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 *block_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)) {
- block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
- parser->command_start = true;
- parser_lex(parser);
- } else {
- block_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(block_parameters, &parser->previous);
- }
-
- uint32_t locals_body_index = 0;
-
- if (block_parameters) {
- locals_body_index = (uint32_t) parser->current_scope->locals.size;
- }
-
- 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, false);
- }
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
- }
-
- pm_node_t *parameters = (pm_node_t *) block_parameters;
- uint8_t maximum = parser->current_scope->numbered_parameters;
-
- if (parameters == NULL && (maximum > 0)) {
- parameters = (pm_node_t *) pm_numbered_parameters_node_create(parser, &(pm_location_t) { .start = opening.start, .end = parser->previous.end }, maximum);
- locals_body_index = maximum;
- }
-
- 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, locals_body_index, &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 accepts_command_call) {
- 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 (accepts_command_call && (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);
-
- // If we have done with the arguments and still not consumed the comma,
- // then we have a trailing comma where we need to check whether it is
- // allowed or not.
- if (parser->previous.type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
- pm_parser_err_previous(parser, PM_ERR_EXPECT_ARGUMENT);
- }
-
- 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, pm_token_t *then_keyword) {
- 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_value_expression(parser, binding_power, true, 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);
-
- if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
- predicate_closed = true;
- *then_keyword = parser->previous;
- }
-
- 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_token_t then_keyword = not_provided(parser);
-
- pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword);
- 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, &then_keyword, statements, NULL, &end_keyword);
- break;
- case PM_CONTEXT_UNLESS:
- parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, 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, &then_keyword);
- 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, &then_keyword, 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
-
-// Assert here that the flags are the same so that we can safely switch the type
-// of the node without having to move the flags.
-PM_STATIC_ASSERT(__LINE__, ((int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING), "Expected the flags to match.");
-
-/**
- * If the encoding was explicitly set through the lexing process, then we need
- * to potentially mark the string's flags to indicate how to encode it.
- */
-static inline pm_node_flags_t
-parse_unescaped_encoding(const pm_parser_t *parser) {
- if (parser->explicit_encoding != NULL) {
- if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
- return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
- } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
- return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
- }
- }
- return 0;
-}
-
-/**
- * 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);
- pm_node_flag_set(node, parse_unescaped_encoding(parser));
-
- 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);
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
- } else {
- 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);
-
- // If we have two string contents in a row, then the content of this
- // symbol is split because of heredoc contents. This looks like:
- //
- // <<A; :'a
- // A
- // b'
- //
- // In this case, the best way we have to represent this is as an
- // interpolated string node, so that's what we'll do here.
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- pm_node_list_t parts = { 0 };
- pm_token_t bounds = not_provided(parser);
-
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
- pm_node_list_append(&parts, part);
-
- part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &parser->current, &bounds, &parser->current_string);
- pm_node_list_append(&parts, part);
-
- if (next_state != PM_LEX_STATE_NONE) {
- lex_state_set(parser, next_state);
- }
-
- parser_lex(parser);
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
- return (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous);
- }
- } 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);
- }
-
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
- } else {
- 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_parameters_p(pm_parser_t *parser) {
- for (pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
- if (scope->numbered_parameters) 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 && pm_token_is_numbered_parameter(parser->previous.start, parser->previous.end)) {
- // 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_parameters_p(parser)) {
- pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE);
- } else {
- // Indicate that this scope is using numbered params so that child
- // scopes cannot.
- uint8_t number = parser->previous.start[1];
-
- // We subtract the value for the character '0' to get the actual
- // integer value of the number (only _1 through _9 are valid)
- uint8_t numbered_parameters = (uint8_t) (number - '0');
- if (numbered_parameters > parser->current_scope->numbered_parameters) {
- parser->current_scope->numbered_parameters = numbered_parameters;
- pm_parser_numbered_parameters_set(parser, numbered_parameters);
- }
-
- // 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 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);
- pm_node_flag_set((pm_node_t *)node, flags);
-
- return (pm_node_t *) node;
-}
-
-/**
- * Parse the method definition name based on the current token available on the
- * parser. If it does not match a valid method definition name, then a missing
- * token is returned.
- */
-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_METHOD_NAME:
- parser_lex(parser);
- return parser->previous;
- case PM_TOKEN_IDENTIFIER:
- pm_refute_numbered_parameter(parser, parser->current.start, parser->current.end);
- 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->opening_loc.start == 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->opening_loc.start == 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->opening_loc.start == 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;
- }
-
- if (match1(parser, PM_TOKEN_USTAR_STAR)) {
- pm_node_t *assoc = parse_pattern_keyword_rest(parser);
-
- if (rest == NULL) {
- rest = assoc;
- } else {
- pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
- pm_node_list_append(&assocs, assoc);
- }
- } 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);
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
-
- if (rest != NULL) {
- pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
- }
-
- 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_token_t name = parser->previous;
- int depth = pm_parser_local_depth(parser, &name);
- if (depth < 0) {
- depth = 0;
- pm_parser_local_add_token(parser, &name);
- }
- return (pm_node_t *) pm_local_variable_target_node_create_depth(parser, &name, (uint32_t) depth);
- }
- 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, false, 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, false, 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, false, 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, false, 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_value_expression(parser, PM_BINDING_POWER_STATEMENT, true, 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;
- int depth = pm_parser_local_depth(parser, &identifier);
- if (depth < 0) {
- depth = 0;
- pm_parser_local_add_token(parser, &identifier);
- }
-
- pm_node_t *target = (pm_node_t *) pm_local_variable_target_node_create_depth(parser, &identifier, (uint32_t) depth);
- 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)) {
- node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
- pm_node_list_append(&nodes, node);
- 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, pm_node_t *current) {
- assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
-
- bool concating = false;
- 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.
- const pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- assert(lex_mode->mode == PM_LEX_STRING);
- bool lex_interpolation = lex_mode->as.string.interpolation;
-
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM);
- // 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;
- pm_token_t content;
- if (match1(parser, PM_TOKEN_EOF)) {
- unescaped = PM_STRING_EMPTY;
- content = not_provided(parser);
- } else {
- unescaped = parser->current_string;
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
- 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 if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_TERM);
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &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 (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
- pm_node_flag_set(node, parse_unescaped_encoding(parser));
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM);
- } 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_flag_set(part, parse_unescaped_encoding(parser));
- 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 if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current);
- } 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 if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current);
- } 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 (current == 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.
- current = 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);
- }
-
- // If we haven't already created our container for concatenation,
- // we'll do that now.
- if (!concating) {
- concating = true;
- pm_token_t bounds = not_provided(parser);
-
- pm_interpolated_string_node_t *container = pm_interpolated_string_node_create(parser, &bounds, NULL, &bounds);
- pm_interpolated_string_node_append(container, current);
- current = (pm_node_t *) container;
- }
-
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node);
- }
- }
-
- return current;
-}
-
-/**
- * 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, bool accepts_command_call) {
- 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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);
- context_push(parser, PM_CONTEXT_PARENS);
- pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, PM_ERR_CANNOT_PARSE_EXPRESSION);
- context_pop(parser);
-
- // 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, true, 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);
- pm_node_flag_set(node, parse_unescaped_encoding(parser));
-
- // Characters can be followed by strings in which case they are
- // automatically concatenated.
- if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- return parse_strings(parser, node);
- }
-
- 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) ||
- (accepts_command_call && (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, accepts_command_call);
- 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, pm_binding_powers[operator.type].left, false, 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, accepts_command_call)) {
- // Since we found arguments, we need to turn off the
- // variable call bit in the flags.
- pm_node_flag_unset((pm_node_t *)call, 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 (
- (accepts_command_call && (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, accepts_command_call);
-
- 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_mode_pop(parser);
- 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_node_flag_set(part, parse_unescaped_encoding(parser));
- 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_mode_pop(parser);
- 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);
- }
- }
-
- size_t common_whitespace = lex_mode->as.heredoc.common_whitespace;
-
- // 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_mode_pop(parser);
- 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_mode_pop(parser);
- 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.
- 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)) {
- return parse_strings(parser, node);
- }
-
- 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: {
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_current(parser, PM_ERR_STATEMENT_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_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, 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, &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_node_t *node;
-
- if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
- pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
-
- // 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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_value_expression(parser, PM_BINDING_POWER_DEFINED, false, 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);
- }
-
- // 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);
- }
-
- node = (pm_node_t *) case_node;
- } else {
- pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
-
- // If this is a case-match node (i.e., it is a pattern matching
- // case statement) then we must have a predicate.
- if (predicate == NULL) {
- pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
- }
-
- // 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_value_expression(parser, PM_BINDING_POWER_DEFINED, true, 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_value_expression(parser, PM_BINDING_POWER_DEFINED, true, 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_match_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);
- }
-
- node = (pm_node_t *) case_node;
- }
-
- 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);
- }
-
- if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
- pm_case_node_consequent_set((pm_case_node_t *) node, else_node);
- } else {
- pm_case_match_node_consequent_set((pm_case_match_node_t *) node, else_node);
- }
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
- if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
- pm_case_node_end_keyword_loc_set((pm_case_node_t *) node, &parser->previous);
- } else {
- pm_case_match_node_end_keyword_loc_set((pm_case_match_node_t *) node, &parser->previous);
- }
-
- return 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, false);
-
- 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: {
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
- }
-
- 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, accepts_command_call);
-
- 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, accepts_command_call);
-
- 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_value_expression(parser, PM_BINDING_POWER_NOT, true, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS);
-
- pm_constant_id_t old_param_name = parser->current_param_name;
- parser->current_param_name = 0;
- 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, false);
- }
-
- 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);
- parser->current_param_name = old_param_name;
- 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, false, 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_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, PM_ERR_CLASS_SUPERCLASS);
- } else {
- inheritance_operator = not_provided(parser);
- superclass = NULL;
- }
-
- pm_constant_id_t old_param_name = parser->current_param_name;
- parser->current_param_name = 0;
- 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, false);
- }
-
- 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);
- parser->current_param_name = old_param_name;
- 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 };
-
- // This context is necessary for lexing `...` in a bare params correctly.
- // It must be pushed before lexing the first param, so it is here.
- context_push(parser, PM_CONTEXT_DEF_PARAMS);
- parser_lex(parser);
- pm_constant_id_t old_param_name = parser->current_param_name;
-
- switch (parser->current.type) {
- case PM_CASE_OPERATOR:
- pm_parser_scope_push(parser, true);
- parser->current_param_name = 0;
- 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);
- parser->current_param_name = 0;
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- parser_lex(parser);
-
- operator = parser->previous;
- name = parse_method_definition_name(parser);
- } else {
- pm_refute_numbered_parameter(parser, parser->previous.start, parser->previous.end);
- pm_parser_scope_push(parser, true);
- parser->current_param_name = 0;
- 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->current_param_name = 0;
- 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: {
- // The current context is `PM_CONTEXT_DEF_PARAMS`, however the inner expression
- // of this parenthesis should not be processed under this context.
- // Thus, the context is popped here.
- context_pop(parser);
- parser_lex(parser);
-
- pm_token_t lparen = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, true, 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);
- parser->current_param_name = 0;
-
- // To push `PM_CONTEXT_DEF_PARAMS` again is for the same reason as described the above.
- context_push(parser, PM_CONTEXT_DEF_PARAMS);
- name = parse_method_definition_name(parser);
- break;
- }
- default:
- pm_parser_scope_push(parser, true);
- parser->current_param_name = 0;
- 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;
- }
- }
-
- uint32_t locals_body_index = (uint32_t) parser->current_scope->locals.size;
-
- 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, binding_power < PM_BINDING_POWER_COMPOSITION, 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, false, 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, true);
- }
-
- 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;
- parser->current_param_name = old_param_name;
- pm_parser_scope_pop(parser);
-
- return (pm_node_t *) pm_def_node_create(
- parser,
- &name,
- receiver,
- params,
- statements,
- &locals,
- locals_body_index,
- &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, true, PM_ERR_DEFINED_EXPRESSION);
-
- if (parser->recovering) {
- rparen = not_provided(parser);
- } else {
- accept1(parser, PM_TOKEN_NEWLINE);
- 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, false, 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: {
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
- }
-
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- if (context_def_p(parser)) {
- pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
- }
-
- 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;
-
- 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, false, 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, false, 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_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_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, 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)) {
- statements = parse_statements(parser, PM_CONTEXT_FOR);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
- }
-
- 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: {
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_current(parser, PM_ERR_STATEMENT_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)) {
- pm_token_t lparen = parser->previous;
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous);
- } else {
- arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
- receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, 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_NOT, true, 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, false, 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_constant_id_t old_param_name = parser->current_param_name;
- parser->current_param_name = 0;
- 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, false);
- }
-
- pm_constant_id_list_t locals = parser->current_scope->locals;
- pm_parser_scope_pop(parser);
- parser->current_param_name = old_param_name;
-
- 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_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, 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_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, 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_token_t opening = parser->previous;
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- 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);
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
- }
- pm_array_node_close_set(array, &closing);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PERCENT_UPPER_I: {
- parser_lex(parser);
- pm_token_t opening = parser->previous;
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- // 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);
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
- }
- pm_array_node_close_set(array, &closing);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PERCENT_LOWER_W: {
- parser_lex(parser);
- pm_token_t opening = parser->previous;
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- // 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);
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
- }
-
- pm_array_node_close_set(array, &closing);
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PERCENT_UPPER_W: {
- parser_lex(parser);
- pm_token_t opening = parser->previous;
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- // 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: {
- // Reset the explicit encoding if we hit a separator
- // since each element can have its own encoding.
- parser->explicit_encoding = NULL;
-
- 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);
- pm_node_flag_set(string, parse_unescaped_encoding(parser));
- 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);
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
- }
-
- pm_array_node_close_set(array, &closing);
- 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);
- }
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
- }
- pm_interpolated_regular_expression_node_closing_set(node, &closing);
-
- 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 (match1(parser, PM_TOKEN_STRING_END)) {
- pm_node_t *node = (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
- pm_node_flag_set(node, parse_unescaped_encoding(parser));
- parser_lex(parser);
- return node;
- }
-
- // 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_node_flag_set(part, parse_unescaped_encoding(parser));
-
- 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);
- }
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
- }
- pm_interpolated_xstring_node_closing_set(node, &closing);
-
- 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, false, 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, binding_power < PM_BINDING_POWER_MATCH, 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, false, 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, false, 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, false, 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, false, 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 *block_parameters;
-
- 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)) {
- block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
- } else {
- block_parameters = 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(block_parameters, &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);
- block_parameters = parse_block_parameters(parser, false, &opening, true);
- pm_accepts_block_stack_pop(parser);
- break;
- }
- default: {
- block_parameters = NULL;
- break;
- }
- }
-
- uint32_t locals_body_index = 0;
-
- if (block_parameters) {
- locals_body_index = (uint32_t) parser->current_scope->locals.size;
- }
-
- 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, false);
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
- }
-
- pm_node_t *parameters = (pm_node_t *) block_parameters;
- uint8_t maximum = parser->current_scope->numbered_parameters;
-
- if (parameters == NULL && (maximum > 0)) {
- parameters = (pm_node_t *) pm_numbered_parameters_node_create(parser, &(pm_location_t) { .start = operator.start, .end = parser->previous.end }, maximum);
- locals_body_index = maximum;
- }
-
- 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, locals_body_index, &operator, &opening, &parser->previous, parameters, 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, false, 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, NULL);
- 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, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
- pm_node_t *value = parse_value_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id);
-
- // Contradicting binding powers, the right-hand-side value of rthe assignment allows the `rescue` modifier.
- if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
- pm_token_t rescue = parser->current;
- parser_lex(parser);
- pm_node_t *right = parse_expression(parser, binding_power, false, PM_ERR_RESCUE_MODIFIER_VALUE);
-
- return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
- }
-
- return value;
-}
-
-
-static inline pm_node_t *
-parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
- pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id);
-
- bool is_single_value = true;
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
- is_single_value = false;
- 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, false, PM_ERR_ARRAY_ELEMENT);
- pm_array_node_elements_append(array, element);
- if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
- }
- }
-
- // Contradicting binding powers, the right-hand-side value of the assignment allows the `rescue` modifier.
- if (is_single_value && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
- pm_token_t rescue = parser->current;
- parser_lex(parser);
- pm_node_t *right = parse_expression(parser, binding_power, false, PM_ERR_RESCUE_MODIFIER_VALUE);
-
- return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
- }
-
- 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;
- }
-}
-
-static bool
-name_is_identifier(pm_parser_t *parser, const uint8_t *source, size_t length) {
- if (length == 0) {
- return false;
- }
-
- size_t width = char_is_identifier_start(parser, source);
- if (!width) {
- return false;
- }
-
- uint8_t *cursor = ((uint8_t *)source) + width;
- while (cursor < source + length && (width = char_is_identifier(parser, cursor))) {
- cursor += width;
- }
-
- return cursor == source + length;
-}
-
-/**
- * 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)) {
- // Since we should not create a MatchWriteNode when all capture names
- // are invalid, creating a MatchWriteNode is delayed here.
- pm_match_write_node_t *match = NULL;
- pm_constant_id_list_t names = { 0 };
-
- for (size_t index = 0; index < named_captures.length; index++) {
- pm_string_t *string = &named_captures.strings[index];
-
- const uint8_t *source = pm_string_source(string);
- size_t length = pm_string_length(string);
-
- pm_location_t location;
- pm_constant_id_t name;
-
- // If the name of the capture group isn't a valid identifier, we do
- // not add it to the local table.
- if (!name_is_identifier(parser, source, length)) continue;
-
- 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.
- location = (pm_location_t) { .start = source, .end = source + length };
- name = pm_parser_constant_id_location(parser, location.start, location.end);
- pm_refute_numbered_parameter(parser, source, source + length);
- } 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.
- location = call->receiver->location;
-
- void *memory = malloc(length);
- if (memory == NULL) abort();
-
- memcpy(memory, source, length);
- // This silences clang analyzer warning about leak of memory pointed by `memory`.
- // NOLINTNEXTLINE(clang-analyzer-*)
- name = pm_parser_constant_id_owned(parser, (const uint8_t *) memory, length);
-
- if (pm_token_is_numbered_parameter(source, source + length)) {
- const pm_location_t *location = &call->receiver->location;
- PM_PARSER_ERR_LOCATION_FORMAT(parser, location, PM_ERR_PARAMETER_NUMBERED_RESERVED, location->start);
- }
- }
-
- if (name != 0) {
- // We dont want to create duplicate targets if the capture name
- // is duplicated.
- if (pm_constant_id_list_includes(&names, name)) continue;
- pm_constant_id_list_append(&names, name);
-
- // Here we lazily create the MatchWriteNode since we know we're
- // about to add a target.
- if (match == NULL) match = pm_match_write_node_create(parser, call);
-
- // First, find the depth of the local that is being assigned.
- int depth;
- if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
- pm_parser_local_add(parser, name);
- }
-
- // Next, create the local variable target and add it to the
- // list of targets for the match.
- pm_node_t *target = (pm_node_t *) pm_local_variable_target_node_create_values(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
- pm_node_list_append(&match->targets, target);
- }
- }
-
- if (match != NULL) {
- result = (pm_node_t *) match;
- } else {
- result = (pm_node_t *) call;
- }
-
- pm_constant_id_list_free(&names);
- } 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, bool accepts_command_call) {
- 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_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, accepts_command_call, 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_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
-
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
-
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
-
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, 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, parser->previous.type == PM_TOKEN_KEYWORD_AND, 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, parser->previous.type == PM_TOKEN_KEYWORD_OR, 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, false, 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, false, 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, false);
- 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, accepts_command_call);
- 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, false, 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_value_expression(parser, binding_power, true, 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_value_expression(parser, binding_power, true, 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_value_expression(parser, binding_power, true, 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_value_expression(parser, binding_power, true, 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: {
- pm_token_t qmark = parser->current;
- parser_lex(parser);
- pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, 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, &qmark, 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, false, PM_ERR_TERNARY_EXPRESSION_FALSE);
-
- return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, 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, accepts_command_call);
- 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, accepts_command_call);
- 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, false);
-
- 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, true, 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, bool accepts_command_call, pm_diagnostic_id_t diag_id) {
- pm_token_t recovery = parser->previous;
- pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_MISSING_NODE:
- // 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.
- pm_parser_err(parser, recovery.end, recovery.end, diag_id);
- return node;
- case PM_PRE_EXECUTION_NODE:
- case PM_POST_EXECUTION_NODE:
- case PM_ALIAS_GLOBAL_VARIABLE_NODE:
- case PM_ALIAS_METHOD_NODE:
- case PM_UNDEF_NODE:
- // These expressions are statements, and cannot be followed by
- // operators (except modifiers).
- if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER_RESCUE) {
- return node;
- }
- break;
- case PM_RANGE_NODE:
- // Range operators are non-associative, so that it does not
- // associate with other range operators (i.e. `..1..` should be
- // rejected.) For this reason, we check such a case for unary ranges
- // here, and if so, it returns the node immediately,
- if ((((pm_range_node_t *) node)->left == NULL) && pm_binding_powers[parser->current.type].left >= PM_BINDING_POWER_RANGE) {
- return node;
- }
- break;
- default:
- break;
- }
-
- // 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, accepts_command_call);
- if (current_binding_powers.nonassoc) {
- bool endless_range_p = PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL;
- pm_binding_power_t left = endless_range_p ? PM_BINDING_POWER_TERM : current_binding_powers.left;
- if (
- left <= pm_binding_powers[parser->current.type].left ||
- // Exceptionally to operator precedences, '1.. & 2' is rejected.
- // '1.. || 2' is also an exception, but it is handled by the lexer.
- // (Here, parser->current is PM_TOKEN_PIPE, not PM_TOKEN_PIPE_PIPE).
- (endless_range_p && match1(parser, PM_TOKEN_AMPERSAND))
- ) {
- break;
- }
- }
- if (accepts_command_call) {
- // A command-style method call is only accepted on method chains.
- // Thus, we check whether the parsed node can continue method chains.
- // The method chain can continue if the parsed node is one of the following five kinds:
- // (1) index access: foo[1]
- // (2) attribute access: foo.bar
- // (3) method call with parenthesis: foo.bar(1)
- // (4) method call with a block: foo.bar do end
- // (5) constant path: foo::Bar
- switch (node->type) {
- case PM_CALL_NODE: {
- pm_call_node_t *cast = (pm_call_node_t *)node;
- if (
- // (1) foo[1]
- !(
- cast->call_operator_loc.start == NULL &&
- cast->message_loc.start != NULL &&
- cast->message_loc.start[0] == '[' &&
- cast->message_loc.end[-1] == ']'
- ) &&
- // (2) foo.bar
- !(
- cast->call_operator_loc.start != NULL &&
- cast->arguments == NULL &&
- cast->block == NULL &&
- cast->opening_loc.start == NULL
- ) &&
- // (3) foo.bar(1)
- !(
- cast->call_operator_loc.start != NULL &&
- cast->opening_loc.start != NULL
- ) &&
- // (4) foo.bar do end
- !(
- cast->block != NULL && PM_NODE_TYPE_P(cast->block, PM_BLOCK_NODE)
- )
- ) {
- accepts_command_call = false;
- }
- break;
- }
- // (5) foo::Bar
- case PM_CONSTANT_PATH_NODE:
- break;
- default:
- accepts_command_call = false;
- break;
- }
- }
- }
-
- 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_ENTRY,
- .encoding_changed_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,
- .explicit_encoding = NULL,
- .command_start = true,
- .recovering = false,
- .encoding_changed = false,
- .pattern_matching_newlines = false,
- .in_keyword_arg = false,
- .current_param_name = 0,
- .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
- 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;
-}
-
-/**
- * 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 };
- 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 };
- 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_varsint(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 869d608c9a..0000000000
--- a/prism/prism.h
+++ /dev/null
@@ -1,272 +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);
-
-/**
- * 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(const 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);
-
-/**
- * Parse the source and return true if it parses without errors or warnings.
- *
- * @param source The source to parse.
- * @param size The size of the source.
- * @param data The optional data to pass to the parser.
- * @return True if the source parses without errors or warnings.
- */
-PRISM_EXPORTED_FUNCTION bool pm_parse_success_p(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(&parser, 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(&parser, root);
- * pm_parser_free(&parser);
- * }
- * ```
- */
-
-#endif
diff --git a/prism/regexp.c b/prism/regexp.c
deleted file mode 100644
index ba498ecc83..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. */
- const 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, const 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, const 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 c5ceab11f9..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/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, const 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 93f67f6551..0000000000
--- a/prism/templates/ext/prism/api_node.c.erb
+++ /dev/null
@@ -1,221 +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, LONG2NUM(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::UInt8Field -%>
-#line <%= __LINE__ + 1 %> "<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = UINT2NUM(cast-><%= field.name %>);
- <%- 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 c169fedf0a..0000000000
--- a/prism/templates/include/prism/ast.h.erb
+++ /dev/null
@@ -1,206 +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))
-
-/**
- * Return true if the given flag is set on the given node.
- */
-#define PM_NODE_FLAG_P(node, flag) ((((pm_node_t *)(node))->flags & (flag)) != 0)
-
-/**
- * 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::UInt8Field then "uint8_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/dot_visitor.rb.erb b/prism/templates/lib/prism/dot_visitor.rb.erb
deleted file mode 100644
index fc3dd4b223..0000000000
--- a/prism/templates/lib/prism/dot_visitor.rb.erb
+++ /dev/null
@@ -1,186 +0,0 @@
-require "cgi"
-
-module Prism
- # This visitor provides the ability to call Node#to_dot, which converts a
- # subtree into a graphviz dot graph.
- class DotVisitor < Visitor
- class Field # :nodoc:
- attr_reader :name, :value, :port
-
- def initialize(name, value, port)
- @name = name
- @value = value
- @port = port
- end
-
- def to_dot
- if port
- "<tr><td align=\"left\" colspan=\"2\" port=\"#{name}\">#{name}</td></tr>"
- else
- "<tr><td align=\"left\">#{name}</td><td>#{CGI.escapeHTML(value)}</td></tr>"
- end
- end
- end
-
- class Table # :nodoc:
- attr_reader :name, :fields
-
- def initialize(name)
- @name = name
- @fields = []
- end
-
- def field(name, value = nil, port: false)
- fields << Field.new(name, value, port)
- end
-
- def to_dot
- dot = <<~DOT
- <table border="0" cellborder="1" cellspacing="0" cellpadding="4">
- <tr><td colspan="2"><b>#{name}</b></td></tr>
- DOT
-
- if fields.any?
- "#{dot} #{fields.map(&:to_dot).join("\n ")}\n</table>"
- else
- "#{dot}</table>"
- end
- end
- end
-
- class Digraph # :nodoc:
- attr_reader :nodes, :waypoints, :edges
-
- def initialize
- @nodes = []
- @waypoints = []
- @edges = []
- end
-
- def node(value)
- nodes << value
- end
-
- def waypoint(value)
- waypoints << value
- end
-
- def edge(value)
- edges << value
- end
-
- def to_dot
- <<~DOT
- digraph "Prism" {
- node [
- fontname=\"Courier New\"
- shape=plain
- style=filled
- fillcolor=gray95
- ];
-
- #{nodes.map { |node| node.gsub(/\n/, "\n ") }.join("\n ")}
- node [shape=point];
- #{waypoints.join("\n ")}
-
- #{edges.join("\n ")}
- }
- DOT
- end
- end
-
- private_constant :Field, :Table, :Digraph
-
- # The digraph that is being built.
- attr_reader :digraph
-
- # Initialize a new dot visitor.
- def initialize
- @digraph = Digraph.new
- end
-
- # Convert this visitor into a graphviz dot graph string.
- def to_dot
- digraph.to_dot
- end
- <%- nodes.each do |node| -%>
-
- # Visit a <%= node.name %> node.
- def visit_<%= node.human %>(node)
- table = Table.new("<%= node.name %>")
- id = node_id(node)
- <%- node.fields.each do |field| -%>
-
- # <%= field.name %>
- <%- case field -%>
- <%- when Prism::NodeField -%>
- table.field("<%= field.name %>", port: true)
- digraph.edge("#{id}:<%= field.name %> -> #{node_id(node.<%= field.name %>)};")
- <%- when Prism::OptionalNodeField -%>
- unless (<%= field.name %> = node.<%= field.name %>).nil?
- table.field("<%= field.name %>", port: true)
- digraph.edge("#{id}:<%= field.name %> -> #{node_id(<%= field.name %>)};")
- end
- <%- when Prism::NodeListField -%>
- if node.<%= field.name %>.any?
- table.field("<%= field.name %>", port: true)
-
- waypoint = "#{id}_<%= field.name %>"
- digraph.waypoint("#{waypoint};")
-
- digraph.edge("#{id}:<%= field.name %> -> #{waypoint};")
- node.<%= field.name %>.each { |child| digraph.edge("#{waypoint} -> #{node_id(child)};") }
- else
- table.field("<%= field.name %>", "[]")
- end
- <%- when Prism::StringField, Prism::ConstantField, Prism::OptionalConstantField, Prism::UInt8Field, Prism::UInt32Field, Prism::ConstantListField -%>
- table.field("<%= field.name %>", node.<%= field.name %>.inspect)
- <%- when Prism::LocationField -%>
- table.field("<%= field.name %>", location_inspect(node.<%= field.name %>))
- <%- when Prism::OptionalLocationField -%>
- unless (<%= field.name %> = node.<%= field.name %>).nil?
- table.field("<%= field.name %>", location_inspect(<%= field.name %>))
- end
- <%- when Prism::FlagsField -%>
- <%- flag = flags.find { |flag| flag.name == field.kind }.tap { |flag| raise "Expected to find #{field.kind}" unless flag } -%>
- table.field("<%= field.name %>", <%= flag.human %>_inspect(node))
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
-
- digraph.nodes << <<~DOT
- #{id} [
- label=<#{table.to_dot.gsub(/\n/, "\n ")}>
- ];
- DOT
-
- super
- end
- <%- end -%>
-
- private
-
- # Generate a unique node ID for a node throughout the digraph.
- def node_id(node)
- "Node_#{node.object_id}"
- end
-
- # Inspect a location to display the start and end line and column numbers.
- def location_inspect(location)
- "(#{location.start_line},#{location.start_column})-(#{location.end_line},#{location.end_column})"
- end
- <%- flags.each do |flag| -%>
-
- # Inspect a node that has <%= flag.human %> flags to display the flags as a
- # comma-separated list.
- def <%= flag.human %>_inspect(node)
- flags = []
- <%- flag.values.each do |value| -%>
- flags << "<%= value.name.downcase %>" if node.<%= value.name.downcase %>?
- <%- end -%>
- flags.join(", ")
- end
- <%- end -%>
- 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 87a94a0338..0000000000
--- a/prism/templates/lib/prism/node.rb.erb
+++ /dev/null
@@ -1,254 +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
-
- # Convert this node into a graphviz dot graph string.
- def to_dot
- DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
- 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 -%>
- <%= 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::UInt8Field, 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 7cbbfb63c5..0000000000
--- a/prism/templates/lib/prism/serialize.rb.erb
+++ /dev/null
@@ -1,310 +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 = 19
-
- # The patch version of prism that we are expecting to find in the serialized
- # strings.
- PATCH_VERSION = 0
-
- # 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 = Encoding.find(io.read(load_varuint))
- @input = input.force_encoding(@encoding).freeze
- @encoding
- end
-
- def load_start_line
- source.start_line = load_varsint
- end
-
- def load_comments
- load_varuint.times.map do
- case load_varuint
- 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_varuint.times.map { MagicComment.new(load_location, load_location) }
- data_loc = load_optional_location
- errors = load_varuint.times.map { ParseError.new(load_embedded_string, load_location) }
- warnings = load_varuint.times.map { ParseWarning.new(load_embedded_string, load_location) }
- [comments, magic_comments, data_loc, errors, warnings]
- end
-
- def load_tokens
- tokens = []
- while type = TOKEN_TYPES.fetch(load_varuint)
- start = load_varuint
- length = load_varuint
- lex_state = load_varuint
- 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, data_loc, errors, warnings = load_metadata
- tokens.each { |token,| token.value.force_encoding(encoding) }
-
- raise "Expected to consume all bytes while deserializing" unless @io.eof?
- Prism::ParseResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, @source)
- end
-
- def load_nodes
- load_header
- load_encoding
- load_start_line
-
- comments, magic_comments, data_loc, errors, warnings = load_metadata
-
- @constant_pool_offset = io.read(4).unpack1("L")
- @constant_pool = Array.new(load_varuint, nil)
-
- [load_node, comments, magic_comments, data_loc, errors, warnings]
- end
-
- def load_result
- node, comments, magic_comments, data_loc, errors, warnings = load_nodes
- Prism::ParseResult.new(node, comments, magic_comments, data_loc, 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_varuint
- 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_varsint
- n = load_varuint
- (n >> 1) ^ (-(n & 1))
- 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_varuint).force_encoding(encoding)
- end
-
- def load_string
- type = io.getbyte
- case type
- when 1
- input.byteslice(load_varuint, load_varuint).force_encoding(encoding)
- when 2
- load_embedded_string
- else
- raise "Unknown serialized string type: #{type}"
- end
- end
-
- def load_location
- Location.new(source, load_varuint, load_varuint)
- 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_varuint - 1)
- end
-
- def load_optional_constant
- index = load_varuint
- 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_varuint) { load_node }"
- when Prism::ConstantField then "load_required_constant"
- when Prism::OptionalConstantField then "load_optional_constant"
- when Prism::ConstantListField then "Array.new(load_varuint) { load_required_constant }"
- when Prism::LocationField then "load_location"
- when Prism::OptionalLocationField then "load_optional_location"
- when Prism::UInt8Field then "io.getbyte"
- when Prism::UInt32Field, Prism::FlagsField then "load_varuint"
- 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_varuint) { load_node }"
- when Prism::ConstantField then "load_required_constant"
- when Prism::OptionalConstantField then "load_optional_constant"
- when Prism::ConstantListField then "Array.new(load_varuint) { load_required_constant }"
- when Prism::LocationField then "load_location"
- when Prism::OptionalLocationField then "load_optional_location"
- when Prism::UInt8Field then "io.getbyte"
- when Prism::UInt32Field, Prism::FlagsField then "load_varuint"
- 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 0552767f4d..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::UInt8Field, 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::UInt8Field, 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::UInt8Field, 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 61831ce59b..0000000000
--- a/prism/templates/src/prettyprint.c.erb
+++ /dev/null
@@ -1,189 +0,0 @@
-<%# encoding: ASCII -%>
-#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, preadd_bytesize = index == node.fields.length - 1 ? ["\\xe2\\x94\\x94\\xe2\\x94\\x80\\xe2\\x94\\x80 ", " ", 4] : ["\\xe2\\x94\\x9c\\xe2\\x94\\x80\\xe2\\x94\\x80 ", "\\xe2\\x94\\x82 ", 6] -%>
-
- // <%= field.name %>
- {
- pm_buffer_concat(output_buffer, prefix_buffer);
- pm_buffer_append_string(output_buffer, "<%= pointer %><%= field.name %>:", <%= 10 + 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, " \xe2\x88\x85\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, "\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ", 10);
- pm_buffer_append_string(prefix_buffer, " ", 4);
- } else {
- pm_buffer_append_string(output_buffer, "\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 ", 10);
- pm_buffer_append_string(prefix_buffer, "\xe2\x94\x82 ", 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, " \xe2\x88\x85\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, " \xe2\x88\x85\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::UInt8Field, 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, " \xe2\x88\x85", 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 e9cdd1e82c..0000000000
--- a/prism/templates/src/serialize.c.erb
+++ /dev/null
@@ -1,380 +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(const pm_parser_t *parser, const pm_location_t *location, pm_buffer_t *buffer) {
- assert(location->start);
- assert(location->end);
- assert(location->start <= location->end);
-
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(location->start - parser->start));
- pm_buffer_append_varuint(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_varuint(buffer, pm_ptrdifft_to_u32(pm_string_source(string) - parser->start));
- pm_buffer_append_varuint(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_varuint(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_varuint(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_varuint(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_varuint(buffer, <%= field.name %>_size);
- for (uint32_t index = 0; index < <%= field.name %>_size; index++) {
- pm_buffer_append_varuint(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::UInt8Field -%>
- pm_buffer_append_byte(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
- <%- when Prism::UInt32Field -%>
- pm_buffer_append_varuint(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
- <%- when Prism::FlagsField -%>
- pm_buffer_append_varuint(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_serialize_location(parser, &comment->location, buffer);
-}
-
-/**
- * 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_varuint(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_varuint(buffer, pm_ptrdifft_to_u32(magic_comment->key_start - parser->start));
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(magic_comment->key_length));
-
- // serialize value location
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(magic_comment->value_start - parser->start));
- pm_buffer_append_varuint(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_varuint(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_data_loc(const pm_parser_t *parser, pm_buffer_t *buffer) {
- if (parser->data_loc.end == NULL) {
- pm_buffer_append_byte(buffer, 0);
- } else {
- pm_buffer_append_byte(buffer, 1);
- pm_serialize_location(parser, &parser->data_loc, 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_varuint(buffer, pm_sizet_to_u32(message_length));
- pm_buffer_append_string(buffer, diagnostic->message, message_length);
-
- // serialize location
- pm_serialize_location(parser, &diagnostic->location, buffer);
-}
-
-static void
-pm_serialize_diagnostic_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
- pm_buffer_append_varuint(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(const pm_encoding_t *encoding, pm_buffer_t *buffer) {
- size_t encoding_length = strlen(encoding->name);
- pm_buffer_append_varuint(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_varsint(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_data_loc(parser, 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_varuint(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_varuint(buffer, token->type);
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(token->start - parser->start));
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(token->end - token->start));
- pm_buffer_append_varuint(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 };
- 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_varsint(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_data_loc(&parser, 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 };
- 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);
-}
-
-/**
- * Parse the source and return true if it parses without errors or warnings.
- */
-PRISM_EXPORTED_FUNCTION bool
-pm_parse_success_p(const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
-
- bool result = parser.error_list.size == 0 && parser.warning_list.size == 0;
- pm_parser_free(&parser);
- pm_options_free(&options);
-
- return result;
-}
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 8cbcf27d79..0000000000
--- a/prism/templates/template.rb
+++ /dev/null
@@ -1,472 +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 UInt8Field < Field
- def rbs_class
- "Integer"
- end
-
- def rbi_class
- "Integer"
- end
-
- def java_type
- "int"
- 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 "uint8" then UInt8Field
- 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
- <<~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 (extension == ".c" || extension == ".h") && !contents.ascii_only?
- # Enforce that we only have ASCII characters here. This is necessary
- # for non-UTF-8 locales that only allow ASCII characters in C source
- # files.
- contents.each_line.with_index(1) do |line, line_number|
- raise "Non-ASCII character on line #{line_number} of #{write_to}" unless line.ascii_only?
- end
- 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",
- "javascript/src/visitor.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/dot_visitor.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 307b55d030..0000000000
--- a/prism/util/pm_buffer.c
+++ /dev/null
@@ -1,179 +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_varuint(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);
- }
-}
-
-/**
- * Append a 32-bit signed integer to the buffer as a variable-length integer.
- */
-void
-pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value) {
- uint32_t unsigned_int = ((uint32_t)(value) << 1) ^ ((uint32_t)(value >> 31));
- pm_buffer_append_varuint(buffer, unsigned_int);
-}
-
-/**
- * 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 ec11d05e9b..0000000000
--- a/prism/util/pm_buffer.h
+++ /dev/null
@@ -1,146 +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_varuint(pm_buffer_t *buffer, uint32_t value);
-
-/**
- * Append a 32-bit signed 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_varsint(pm_buffer_t *buffer, int32_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 7ea20ace6d..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, const 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 e0671eaed3..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/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, const 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 115eba1fd2..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(const 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(const 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 c1cf0d54db..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 to search.
- * @param charset The charset to search for.
- * @param length The maximum number of bytes 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(const 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 1472c58be6..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 19
-
-/**
- * The patch version of the Prism library as an int.
- */
-#define PRISM_VERSION_PATCH 0
-
-/**
- * The version of the Prism library as a constant string.
- */
-#define PRISM_VERSION "0.19.0"
-
-#endif
diff --git a/prism_compile.c b/prism_compile.c
deleted file mode 100644
index b60ca0ac68..0000000000
--- a/prism_compile.c
+++ /dev/null
@@ -1,6532 +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;
-
-#define PM_NOP \
- ADD_INSN(ret, &dummy_line_node, nop);
-
-/**
- * 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)
-{
- char *start = (char *) node->base.location.start;
- char *end = (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, &end, 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);
-}
-
-/**
- * Certain strings can have their encoding differ from the parser's encoding due
- * to bytes or escape sequences that have the top bit set. This function handles
- * creating those strings based on the flags set on the owning node.
- */
-static inline VALUE
-parse_string_encoded(const pm_node_t *node, const pm_string_t *string, const pm_parser_t *parser) {
- rb_encoding *encoding;
-
- if (node->flags & PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING) {
- encoding = rb_ascii8bit_encoding();
- } else if (node->flags & PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING) {
- encoding = rb_utf8_encoding();
- } else {
- encoding = 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), encoding);
-}
-
-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(const 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;
- }
-}
-
-/**
- * Currently, the ADD_INSN family of macros expects a NODE as the second
- * parameter. It uses this node to determine the line number and the node ID for
- * the instruction.
- *
- * Because prism does not use the NODE struct (or have node IDs for that matter)
- * we need to generate a dummy node to pass to these macros. We also need to use
- * the line number from the node to generate labels.
- *
- * We use this struct to store the dummy node and the line number together so
- * that we can use it while we're compiling code.
- *
- * In the future, we'll need to eventually remove this dependency and figure out
- * a more permanent solution. For the line numbers, this shouldn't be too much
- * of a problem, we can redefine the ADD_INSN family of macros. For the node ID,
- * we can probably replace it directly with the column information since we have
- * that at the time that we're generating instructions. In theory this could
- * make node ID unnecessary.
- */
-typedef struct {
- NODE node;
- int lineno;
-} pm_line_node_t;
-
-/**
- * The function generates a dummy node and stores the line number after it looks
- * it up for the given scope and node. (The scope in this case is just used
- * because it holds a reference to the parser, which holds a reference to the
- * newline list that we need to look up the line numbers.)
- */
-static void
-pm_line_node(pm_line_node_t *line_node, const pm_scope_node_t *scope_node, const pm_node_t *node)
-{
- // First, clear out the pointer.
- memset(line_node, 0, sizeof(pm_line_node_t));
-
- // Next, retrieve the line and column information from prism.
- pm_line_column_t line_column = pm_newline_list_line_column(&scope_node->parser->newline_list, node->location.start);
-
- // Next, use the line number for the dummy node.
- int lineno = (int) line_column.line;
-
- nd_set_line(&line_node->node, lineno);
- nd_set_node_id(&line_node->node, lineno);
- line_node->lineno = lineno;
-}
-
-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;
- }
-}
-
-// This recurses through scopes and finds the local index at any scope level
-// It also takes a pointer to depth, and increments depth appropriately
-// according to the depth of the local
-static int
-pm_lookup_local_index_any_scope(rb_iseq_t *iseq, pm_scope_node_t *scope_node, pm_constant_id_t constant_id)
-{
- if (!scope_node) {
- // We have recursed up all scope nodes
- // and have not found the local yet
- rb_bug("This local does not exist");
- }
-
- st_data_t local_index;
-
- if (!st_lookup(scope_node->index_lookup_table, constant_id, &local_index)) {
- // Local does not exist at this level, continue recursing up
- return pm_lookup_local_index_any_scope(iseq, scope_node->previous, constant_id);
- }
-
- return scope_node->local_table_for_iseq_size - (int)local_index;
-}
-
-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;
-
- if (!st_lookup(scope_node->index_lookup_table, constant_id, &local_index)) {
- rb_bug("This local does not exist");
- }
-
- return scope_node->local_table_for_iseq_size - (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_any_scope(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_bug("[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, bool safe_nav, 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 *else_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);
-
- if (safe_nav) {
- PM_DUP;
- ADD_INSNL(ret, &dummy_line_node, branchnil, else_label);
- }
-
- 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;
- }
-
- if (safe_nav) {
- ADD_LABEL(ret, else_label);
- }
-
- ADD_LABEL(ret, end_label);
- PM_POP;
- return;
-}
-
-static void
-pm_compile_index_write_nodes_add_send(bool popped, LINK_ANCHOR *const ret, rb_iseq_t *iseq, NODE dummy_line_node, VALUE argc, int flag, int block_offset)
-{
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, setn, FIXNUM_INC(argc, 2 + block_offset));
- }
-
- if (flag & VM_CALL_ARGS_SPLAT) {
- ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(1));
- if (block_offset > 0) {
- ADD_INSN1(ret, &dummy_line_node, dupn, INT2FIX(3));
- PM_SWAP;
- PM_POP;
- }
- ADD_INSN(ret, &dummy_line_node, concatarray);
- if (block_offset > 0) {
- ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(3));
- PM_POP;
- }
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idASET, argc, INT2FIX(flag));
- }
- else {
- if (block_offset > 0) {
- PM_SWAP;
- }
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
- }
-
- PM_POP;
- return;
-}
-
-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_CONTAINS_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_NOT_POPPED(assoc->key);
- PM_COMPILE_NOT_POPPED(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;
- }
-
- *flags |= VM_CALL_KW_SPLAT_MUT;
- }
-
- pm_assoc_splat_node_t *assoc_splat = (pm_assoc_splat_node_t *)cur_node;
- PM_COMPILE_NOT_POPPED(assoc_splat->value);
-
- *flags |= VM_CALL_KW_SPLAT;
-
- 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 {
- // We need to first figure out if all elements of the KeywordHashNode are AssocNodes
- // with symbol keys.
- if (PM_NODE_FLAG_P(keyword_arg, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS)) {
- // If they are all symbol keys then we can pass them as keyword arguments.
- *kw_arg = rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
- *flags |= VM_CALL_KWARG;
- VALUE *keywords = (*kw_arg)->keywords;
- (*kw_arg)->references = 0;
- (*kw_arg)->keyword_len = (int)len;
-
- for (size_t i = 0; i < len; i++) {
- pm_assoc_node_t *assoc = (pm_assoc_node_t *)keyword_arg->elements.nodes[i];
- pm_node_t *key = assoc->key;
- keywords[i] = pm_static_literal_value(key, scope_node, parser);
- PM_COMPILE_NOT_POPPED(assoc->value);
- }
- } else {
- // If they aren't all symbol keys then we need to construct a new hash
- // and pass that as an argument.
- orig_argc++;
- *flags |= VM_CALL_KW_SPLAT;
- if (len > 1) {
- // A new hash will be created for the keyword arguments in this case,
- // so mark the method as passing mutable keyword splat.
- *flags |= VM_CALL_KW_SPLAT_MUT;
- }
-
- for (size_t i = 0; i < len; i++) {
- pm_assoc_node_t *assoc = (pm_assoc_node_t *)keyword_arg->elements.nodes[i];
- PM_COMPILE_NOT_POPPED(assoc->key);
- PM_COMPILE_NOT_POPPED(assoc->value);
- }
-
- ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(len * 2));
- }
- }
- 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, Qfalse);
-
- 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) {
- if (post_splat_counter > 1) {
- 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);
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(post_splat_counter));
- ADD_INSN(ret, &dummy_line_node, concatarray);
- }
- orig_argc = 1;
- }
- }
- }
- }
- }
- }
- return orig_argc;
-}
-
-static void
-pm_compile_index_and_or_write_node(bool and_node, pm_node_t *receiver, pm_node_t *value, pm_arguments_node_t *arguments, pm_node_t *block, LINK_ANCHOR *const ret, rb_iseq_t *iseq, int lineno, const uint8_t * src, bool popped, pm_scope_node_t *scope_node, pm_parser_t *parser)
-{
- NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
- PM_PUTNIL_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(receiver);
-
- int flag = 0;
- int argc_int = 0;
-
- if (arguments) {
- // Get any arguments, and set the appropriate values for flag
- argc_int = pm_setup_args(arguments, &flag, NULL, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
- }
-
- VALUE argc = INT2FIX(argc_int);
- int block_offset = 0;
-
- if (block) {
- PM_COMPILE_NOT_POPPED(block);
- flag |= VM_CALL_ARGS_BLOCKARG;
- block_offset = 1;
- }
-
- ADD_INSN1(ret, &dummy_line_node, dupn, FIXNUM_INC(argc, 1 + block_offset));
-
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idAREF, argc, INT2FIX(flag));
-
- LABEL *label = NEW_LABEL(lineno);
- LABEL *lfin = NEW_LABEL(lineno);
-
- PM_DUP;
-
- if (and_node) {
- ADD_INSNL(ret, &dummy_line_node, branchunless, label);
- }
- else {
- // ornode
- ADD_INSNL(ret, &dummy_line_node, branchif, label);
- }
-
- PM_POP;
-
- PM_COMPILE_NOT_POPPED(value);
-
- pm_compile_index_write_nodes_add_send(popped, ret, iseq, dummy_line_node, argc, flag, block_offset);
-
- ADD_INSNL(ret, &dummy_line_node, jump, lfin);
- ADD_LABEL(ret, label);
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, setn, FIXNUM_INC(argc, 2 + block_offset));
- }
- ADD_INSN1(ret, &dummy_line_node, adjuststack, FIXNUM_INC(argc, 2 + block_offset));
- ADD_LABEL(ret, lfin);
-
- 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 uint8_t *src, bool popped, 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_INDEX_TARGET_NODE: {
- pm_index_target_node_t *cast = (pm_index_target_node_t *)node;
- PM_COMPILE_NOT_POPPED((pm_node_t *)cast->receiver);
- pushed++;
-
- if (cast->arguments) {
- for (size_t i = 0; i < cast->arguments->arguments.size; i++) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)cast->arguments->arguments.nodes[i]);
- }
- pushed += cast->arguments->arguments.size;
- }
- break;
- }
- case PM_CALL_TARGET_NODE: {
- pm_call_target_node_t *cast = (pm_call_target_node_t *)node;
- PM_COMPILE_NOT_POPPED((pm_node_t *)cast->receiver);
- pushed++;
- break;
- }
- 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, src, popped, 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, src, popped, 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, src, popped, 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, src, popped, 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;
-}
-
-// When we compile a pattern matching expression, we use the stack as a scratch
-// space to store lots of different values (consider it like we have a pattern
-// matching function and we need space for a bunch of different local
-// variables). The "base index" refers to the index on the stack where we
-// started compiling the pattern matching expression. These offsets from that
-// base index indicate the location of the various locals we need.
-#define PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE 0
-#define PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING 1
-#define PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P 2
-#define PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE 3
-#define PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY 4
-
-// A forward declaration because this is the recursive function that handles
-// compiling a pattern. It can be reentered by nesting patterns, as in the case
-// of arrays or hashes.
-static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index);
-
-/**
- * This function generates the code to set up the error string and error_p
- * locals depending on whether or not the pattern matched.
- */
-static int
-pm_compile_pattern_generic_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, unsigned int base_index)
-{
- pm_line_node_t line;
- pm_line_node(&line, scope_node, node);
-
- LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
-
- ADD_INSN(ret, &line.node, dup);
- ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
-
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, putobject, message);
- ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
- ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(2));
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
-
- ADD_INSN1(ret, &line.node, putobject, Qfalse);
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
-
- ADD_INSN(ret, &line.node, pop);
- ADD_INSN(ret, &line.node, pop);
- ADD_LABEL(ret, match_succeeded_label);
-
- return COMPILE_OK;
-}
-
-/**
- * This function generates the code to set up the error string and error_p
- * locals depending on whether or not the pattern matched when the value needs
- * to match a specific deconstructed length.
- */
-static int
-pm_compile_pattern_length_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, VALUE length, unsigned int base_index)
-{
- pm_line_node_t line;
- pm_line_node(&line, scope_node, node);
-
- LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
-
- ADD_INSN(ret, &line.node, dup);
- ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
-
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, putobject, message);
- ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
- ADD_INSN(ret, &line.node, dup);
- ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
- ADD_INSN1(ret, &line.node, putobject, length);
- ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(4));
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
-
- ADD_INSN1(ret, &line.node, putobject, Qfalse);
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
-
- ADD_INSN(ret, &line.node, pop);
- ADD_INSN(ret, &line.node, pop);
- ADD_LABEL(ret, match_succeeded_label);
-
- return COMPILE_OK;
-}
-
-/**
- * This function generates the code to set up the error string and error_p
- * locals depending on whether or not the pattern matched when the value needs
- * to pass a specific #=== method call.
- */
-static int
-pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, unsigned int base_index)
-{
- pm_line_node_t line;
- pm_line_node(&line, scope_node, node);
-
- LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
-
- ADD_INSN(ret, &line.node, dup);
- ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
-
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("%p === %p does not return true"));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(5));
- ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(3));
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
- ADD_INSN1(ret, &line.node, putobject, Qfalse);
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
- ADD_INSN(ret, &line.node, pop);
- ADD_INSN(ret, &line.node, pop);
-
- ADD_LABEL(ret, match_succeeded_label);
- ADD_INSN1(ret, &line.node, setn, INT2FIX(2));
- ADD_INSN(ret, &line.node, pop);
- ADD_INSN(ret, &line.node, pop);
-
- return COMPILE_OK;
-}
-
-/**
- * This is a variation on compiling a pattern matching expression that is used
- * to have the pattern matching instructions fall through to immediately after
- * the pattern if it passes. Otherwise it jumps to the given unmatched_label
- * label.
- */
-static int
-pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
-{
- LABEL *matched_label = NEW_LABEL(nd_line(node));
- CHECK(pm_compile_pattern(iseq, scope_node, node, ret, src, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
- ADD_LABEL(ret, matched_label);
- return COMPILE_OK;
-}
-
-/**
- * This function compiles in the code necessary to call #deconstruct on the
- * value to match against. It raises appropriate errors if the method does not
- * exist or if it returns the wrong type.
- */
-static int
-pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *deconstruct_label, LABEL *match_failed_label, LABEL *deconstructed_label, LABEL *type_error_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index)
-{
- pm_line_node_t line;
- pm_line_node(&line, scope_node, node);
-
- if (use_deconstructed_cache) {
- ADD_INSN1(ret, &line.node, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
- ADD_INSNL(ret, &line.node, branchnil, deconstruct_label);
-
- ADD_INSN1(ret, &line.node, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
- ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
-
- ADD_INSN(ret, &line.node, pop);
- ADD_INSN1(ret, &line.node, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE - 1));
- ADD_INSNL(ret, &line.node, jump, deconstructed_label);
- } else {
- ADD_INSNL(ret, &line.node, jump, deconstruct_label);
- }
-
- ADD_LABEL(ret, deconstruct_label);
- ADD_INSN(ret, &line.node, dup);
- ADD_INSN1(ret, &line.node, putobject, ID2SYM(rb_intern("deconstruct")));
- ADD_SEND(ret, &line.node, idRespond_to, INT2FIX(1));
-
- if (use_deconstructed_cache) {
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE + 1));
- }
-
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1));
- }
-
- ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
- ADD_SEND(ret, &line.node, rb_intern("deconstruct"), INT2FIX(0));
-
- if (use_deconstructed_cache) {
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
- }
-
- ADD_INSN(ret, &line.node, dup);
- ADD_INSN1(ret, &line.node, checktype, INT2FIX(T_ARRAY));
- ADD_INSNL(ret, &line.node, branchunless, type_error_label);
- ADD_LABEL(ret, deconstructed_label);
-
- return COMPILE_OK;
-}
-
-/**
- * This function compiles in the code necessary to match against the optional
- * constant path that is attached to an array, find, or hash pattern.
- */
-static int
-pm_compile_pattern_constant(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *match_failed_label, bool in_single_pattern, unsigned int base_index)
-{
- pm_line_node_t line;
- pm_line_node(&line, scope_node, node);
-
- ADD_INSN(ret, &line.node, dup);
- PM_COMPILE_NOT_POPPED(node);
-
- if (in_single_pattern) {
- ADD_INSN1(ret, &line.node, dupn, INT2FIX(2));
- }
- ADD_INSN1(ret, &line.node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_eqq_error(iseq, scope_node, node, ret, base_index + 3));
- }
- ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
- return COMPILE_OK;
-}
-
-/**
- * When matching fails, an appropriate error must be raised. This function is
- * responsible for compiling in those error raising instructions.
- */
-static void
-pm_compile_pattern_error_handler(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *done_label, bool popped)
-{
- pm_line_node_t line;
- pm_line_node(&line, scope_node, node);
-
- LABEL *key_error_label = NEW_LABEL(line.lineno);
- LABEL *cleanup_label = NEW_LABEL(line.lineno);
-
- struct rb_callinfo_kwarg *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"));
-
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
- ADD_INSNL(ret, &line.node, branchif, key_error_label);
-
- ADD_INSN1(ret, &line.node, putobject, rb_eNoMatchingPatternError);
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("%p: %s"));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(4));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 6));
- ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(3));
- ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(2));
- ADD_INSNL(ret, &line.node, jump, cleanup_label);
-
- ADD_LABEL(ret, key_error_label);
- ADD_INSN1(ret, &line.node, putobject, rb_eNoMatchingPatternKeyError);
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("%p: %s"));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(4));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 6));
- ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(3));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE + 4));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY + 5));
- ADD_SEND_R(ret, &line.node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
- ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(1));
- ADD_LABEL(ret, cleanup_label);
-
- ADD_INSN1(ret, &line.node, adjuststack, INT2FIX(7));
- if (!popped) ADD_INSN(ret, &line.node, putnil);
- ADD_INSNL(ret, &line.node, jump, done_label);
- ADD_INSN1(ret, &line.node, dupn, INT2FIX(5));
- if (popped) ADD_INSN(ret, &line.node, putnil);
-}
-
-/**
- * Compile a pattern matching expression.
- */
-static int
-pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
-{
- pm_line_node_t line;
- pm_line_node(&line, scope_node, node);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_ARRAY_PATTERN_NODE: {
- // Array patterns in pattern matching are triggered by using commas in
- // a pattern or wrapping it in braces. They are represented by a
- // ArrayPatternNode. This looks like:
- //
- // foo => [1, 2, 3]
- //
- // It can optionally have a splat in the middle of it, which can
- // optionally have a name attached.
- const pm_array_pattern_node_t *cast = (const pm_array_pattern_node_t *) node;
-
- const size_t requireds_size = cast->requireds.size;
- const size_t posts_size = cast->posts.size;
- const size_t minimum_size = requireds_size + posts_size;
-
- bool use_rest_size = (
- cast->rest != NULL &&
- PM_NODE_TYPE_P(cast->rest, PM_SPLAT_NODE) &&
- ((((const pm_splat_node_t *) cast->rest)->expression != NULL) || posts_size > 0)
- );
-
- LABEL *match_failed_label = NEW_LABEL(line.lineno);
- LABEL *type_error_label = NEW_LABEL(line.lineno);
- LABEL *deconstruct_label = NEW_LABEL(line.lineno);
- LABEL *deconstructed_label = NEW_LABEL(line.lineno);
-
- if (use_rest_size) {
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(0));
- ADD_INSN(ret, &line.node, swap);
- base_index++;
- }
-
- if (cast->constant != NULL) {
- CHECK(pm_compile_pattern_constant(iseq, scope_node, cast->constant, ret, src, match_failed_label, in_single_pattern, base_index));
- }
-
- CHECK(pm_compile_pattern_deconstruct(iseq, scope_node, node, ret, src, deconstruct_label, match_failed_label, deconstructed_label, type_error_label, in_single_pattern, use_deconstructed_cache, base_index));
-
- ADD_INSN(ret, &line.node, dup);
- ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(minimum_size));
- ADD_SEND(ret, &line.node, cast->rest == NULL ? idEq : idGE, INT2FIX(1));
- if (in_single_pattern) {
- VALUE message = cast->rest == NULL ? rb_fstring_lit("%p length mismatch (given %p, expected %p)") : rb_fstring_lit("%p length mismatch (given %p, expected %p+)");
- CHECK(pm_compile_pattern_length_error(iseq, scope_node, node, ret, message, INT2FIX(minimum_size), base_index + 1));
- }
- ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
-
- for (size_t index = 0; index < requireds_size; index++) {
- const pm_node_t *required = cast->requireds.nodes[index];
- ADD_INSN(ret, &line.node, dup);
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(index));
- ADD_SEND(ret, &line.node, idAREF, INT2FIX(1));
- CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
- }
-
- if (cast->rest != NULL) {
- if (((const pm_splat_node_t *) cast->rest)->expression != NULL) {
- ADD_INSN(ret, &line.node, dup);
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(requireds_size));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(1));
- ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(minimum_size));
- ADD_SEND(ret, &line.node, idMINUS, INT2FIX(1));
- ADD_INSN1(ret, &line.node, setn, INT2FIX(4));
- ADD_SEND(ret, &line.node, idAREF, INT2FIX(2));
- CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
- } else if (posts_size > 0) {
- ADD_INSN(ret, &line.node, dup);
- ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(minimum_size));
- ADD_SEND(ret, &line.node, idMINUS, INT2FIX(1));
- ADD_INSN1(ret, &line.node, setn, INT2FIX(2));
- ADD_INSN(ret, &line.node, pop);
- }
- }
-
- for (size_t index = 0; index < posts_size; index++) {
- const pm_node_t *post = cast->posts.nodes[index];
- ADD_INSN(ret, &line.node, dup);
-
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(requireds_size + index));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
- ADD_SEND(ret, &line.node, idPLUS, INT2FIX(1));
- ADD_SEND(ret, &line.node, idAREF, INT2FIX(1));
- CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
- }
-
- ADD_INSN(ret, &line.node, pop);
- if (use_rest_size) {
- ADD_INSN(ret, &line.node, pop);
- }
-
- ADD_INSNL(ret, &line.node, jump, matched_label);
- ADD_INSN(ret, &line.node, putnil);
- if (use_rest_size) {
- ADD_INSN(ret, &line.node, putnil);
- }
-
- ADD_LABEL(ret, type_error_label);
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, putobject, rb_eTypeError);
- ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("deconstruct must return Array"));
- ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(2));
- ADD_INSN(ret, &line.node, pop);
-
- ADD_LABEL(ret, match_failed_label);
- ADD_INSN(ret, &line.node, pop);
- if (use_rest_size) {
- ADD_INSN(ret, &line.node, pop);
- }
-
- ADD_INSNL(ret, &line.node, jump, unmatched_label);
- break;
- }
- case PM_FIND_PATTERN_NODE: {
- // Find patterns in pattern matching are triggered by using commas in
- // a pattern or wrapping it in braces and using a splat on both the left
- // and right side of the pattern. This looks like:
- //
- // foo => [*, 1, 2, 3, *]
- //
- // There can be any number of requireds in the middle. The splats on
- // both sides can optionally have names attached.
- const pm_find_pattern_node_t *cast = (const pm_find_pattern_node_t *) node;
- const size_t size = cast->requireds.size;
-
- LABEL *match_failed_label = NEW_LABEL(line.lineno);
- LABEL *type_error_label = NEW_LABEL(line.lineno);
- LABEL *deconstruct_label = NEW_LABEL(line.lineno);
- LABEL *deconstructed_label = NEW_LABEL(line.lineno);
-
- if (cast->constant) {
- CHECK(pm_compile_pattern_constant(iseq, scope_node, cast->constant, ret, src, match_failed_label, in_single_pattern, base_index));
- }
-
- CHECK(pm_compile_pattern_deconstruct(iseq, scope_node, node, ret, src, deconstruct_label, match_failed_label, deconstructed_label, type_error_label, in_single_pattern, use_deconstructed_cache, base_index));
-
- ADD_INSN(ret, &line.node, dup);
- ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(size));
- ADD_SEND(ret, &line.node, idGE, INT2FIX(1));
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_length_error(iseq, scope_node, node, ret, rb_fstring_lit("%p length mismatch (given %p, expected %p+)"), INT2FIX(size), base_index + 1));
- }
- ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
-
- {
- LABEL *while_begin_label = NEW_LABEL(line.lineno);
- LABEL *next_loop_label = NEW_LABEL(line.lineno);
- LABEL *find_succeeded_label = NEW_LABEL(line.lineno);
- LABEL *find_failed_label = NEW_LABEL(line.lineno);
-
- ADD_INSN(ret, &line.node, dup);
- ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
-
- ADD_INSN(ret, &line.node, dup);
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(size));
- ADD_SEND(ret, &line.node, idMINUS, INT2FIX(1));
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(0));
- ADD_LABEL(ret, while_begin_label);
-
- ADD_INSN(ret, &line.node, dup);
- ADD_INSN1(ret, &line.node, topn, INT2FIX(2));
- ADD_SEND(ret, &line.node, idLE, INT2FIX(1));
- ADD_INSNL(ret, &line.node, branchunless, find_failed_label);
-
- for (size_t index = 0; index < size; index++) {
- ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(1));
-
- if (index != 0) {
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(index));
- ADD_SEND(ret, &line.node, idPLUS, INT2FIX(1));
- }
-
- ADD_SEND(ret, &line.node, idAREF, INT2FIX(1));
- CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, src, next_loop_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
- }
-
- assert(PM_NODE_TYPE_P(cast->left, PM_SPLAT_NODE));
- const pm_splat_node_t *left = (const pm_splat_node_t *) cast->left;
-
- if (left->expression != NULL) {
- 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));
- CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, src, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
- }
-
- assert(PM_NODE_TYPE_P(cast->right, PM_SPLAT_NODE));
- const pm_splat_node_t *right = (const pm_splat_node_t *) cast->right;
-
- if (right->expression != NULL) {
- ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(1));
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(size));
- ADD_SEND(ret, &line.node, idPLUS, INT2FIX(1));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
- ADD_SEND(ret, &line.node, idAREF, INT2FIX(2));
- pm_compile_pattern_match(iseq, scope_node, right->expression, ret, src, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4);
- }
-
- ADD_INSNL(ret, &line.node, jump, find_succeeded_label);
-
- ADD_LABEL(ret, next_loop_label);
- ADD_INSN1(ret, &line.node, putobject, INT2FIX(1));
- ADD_SEND(ret, &line.node, idPLUS, INT2FIX(1));
- ADD_INSNL(ret, &line.node, jump, while_begin_label);
-
- ADD_LABEL(ret, find_failed_label);
- ADD_INSN1(ret, &line.node, adjuststack, INT2FIX(3));
- if (in_single_pattern) {
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("%p does not match to find pattern"));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(2));
- ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(2));
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
-
- ADD_INSN1(ret, &line.node, putobject, Qfalse);
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
-
- ADD_INSN(ret, &line.node, pop);
- ADD_INSN(ret, &line.node, pop);
- }
- ADD_INSNL(ret, &line.node, jump, match_failed_label);
- ADD_INSN1(ret, &line.node, dupn, INT2FIX(3));
-
- ADD_LABEL(ret, find_succeeded_label);
- ADD_INSN1(ret, &line.node, adjuststack, INT2FIX(3));
- }
-
- ADD_INSN(ret, &line.node, pop);
- ADD_INSNL(ret, &line.node, jump, matched_label);
- ADD_INSN(ret, &line.node, putnil);
-
- ADD_LABEL(ret, type_error_label);
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, putobject, rb_eTypeError);
- ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("deconstruct must return Array"));
- ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(2));
- ADD_INSN(ret, &line.node, pop);
-
- ADD_LABEL(ret, match_failed_label);
- ADD_INSN(ret, &line.node, pop);
- ADD_INSNL(ret, &line.node, jump, unmatched_label);
-
- break;
- }
- case PM_HASH_PATTERN_NODE: {
- // Hash patterns in pattern matching are triggered by using labels and
- // values in a pattern or by using the ** operator. They are represented
- // by the HashPatternNode. This looks like:
- //
- // foo => { a: 1, b: 2, **bar }
- //
- // It can optionally have an assoc splat in the middle of it, which can
- // optionally have a name.
- const pm_hash_pattern_node_t *cast = (const pm_hash_pattern_node_t *) node;
-
- // We don't consider it a "rest" parameter if it's a ** that is unnamed.
- bool has_rest = cast->rest != NULL && !(PM_NODE_TYPE_P(cast->rest, PM_ASSOC_SPLAT_NODE) && ((const pm_assoc_splat_node_t *) cast->rest)->value == NULL);
- bool has_keys = cast->elements.size > 0 || cast->rest != NULL;
-
- LABEL *match_failed_label = NEW_LABEL(line.lineno);
- LABEL *type_error_label = NEW_LABEL(line.lineno);
- VALUE keys = Qnil;
-
- if (has_keys && !has_rest) {
- keys = rb_ary_new_capa(cast->elements.size);
-
- for (size_t index = 0; index < cast->elements.size; index++) {
- const pm_node_t *element = cast->elements.nodes[index];
- assert(PM_NODE_TYPE_P(element, PM_ASSOC_NODE));
-
- const pm_node_t *key = ((const pm_assoc_node_t *) element)->key;
- assert(PM_NODE_TYPE_P(key, PM_SYMBOL_NODE));
-
- VALUE symbol = ID2SYM(parse_string_symbol(&((const pm_symbol_node_t *) key)->unescaped, scope_node->parser));
- rb_ary_push(keys, symbol);
- }
- }
-
- if (cast->constant) {
- CHECK(pm_compile_pattern_constant(iseq, scope_node, cast->constant, ret, src, match_failed_label, in_single_pattern, base_index));
- }
-
- ADD_INSN(ret, &line.node, dup);
- ADD_INSN1(ret, &line.node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
- ADD_SEND(ret, &line.node, idRespond_to, INT2FIX(1));
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1));
- }
- ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
-
- if (NIL_P(keys)) {
- ADD_INSN(ret, &line.node, putnil);
- } else {
- ADD_INSN1(ret, &line.node, duparray, keys);
- RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
- }
- ADD_SEND(ret, &line.node, rb_intern("deconstruct_keys"), INT2FIX(1));
-
- ADD_INSN(ret, &line.node, dup);
- ADD_INSN1(ret, &line.node, checktype, INT2FIX(T_HASH));
- ADD_INSNL(ret, &line.node, branchunless, type_error_label);
-
- if (has_rest) {
- ADD_SEND(ret, &line.node, rb_intern("dup"), INT2FIX(0));
- }
-
- if (has_keys) {
- DECL_ANCHOR(match_values);
- INIT_ANCHOR(match_values);
-
- for (size_t index = 0; index < cast->elements.size; index++) {
- const pm_node_t *element = cast->elements.nodes[index];
- assert(PM_NODE_TYPE_P(element, PM_ASSOC_NODE));
-
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
- const pm_node_t *key = assoc->key;
- assert(PM_NODE_TYPE_P(key, PM_SYMBOL_NODE));
-
- VALUE symbol = ID2SYM(parse_string_symbol(&((const pm_symbol_node_t *) key)->unescaped, scope_node->parser));
- ADD_INSN(ret, &line.node, dup);
- ADD_INSN1(ret, &line.node, putobject, symbol);
- ADD_SEND(ret, &line.node, rb_intern("key?"), INT2FIX(1));
-
- if (in_single_pattern) {
- LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
-
- ADD_INSN(ret, &line.node, dup);
- ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
-
- ADD_INSN1(ret, &line.node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, symbol)));
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 2));
- ADD_INSN1(ret, &line.node, putobject, Qtrue);
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 3));
- ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE + 4));
- ADD_INSN1(ret, &line.node, putobject, symbol);
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY + 5));
-
- ADD_INSN1(ret, &line.node, adjuststack, INT2FIX(4));
- ADD_LABEL(ret, match_succeeded_label);
- }
-
- ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
- ADD_INSN(match_values, &line.node, dup);
- ADD_INSN1(match_values, &line.node, putobject, symbol);
- ADD_SEND(match_values, &line.node, has_rest ? rb_intern("delete") : idAREF, INT2FIX(1));
-
- CHECK(pm_compile_pattern_match(iseq, scope_node, assoc->value, match_values, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
- }
-
- ADD_SEQ(ret, match_values);
- } else {
- ADD_INSN(ret, &line.node, dup);
- ADD_SEND(ret, &line.node, idEmptyP, INT2FIX(0));
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("%p is not empty"), base_index + 1));
- }
- ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
- }
-
- if (has_rest) {
- switch (PM_NODE_TYPE(cast->rest)) {
- case PM_NO_KEYWORDS_PARAMETER_NODE: {
- ADD_INSN(ret, &line.node, dup);
- ADD_SEND(ret, &line.node, idEmptyP, INT2FIX(0));
- if (in_single_pattern) {
- pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("rest of %p is not empty"), base_index + 1);
- }
- ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
- break;
- }
- case PM_ASSOC_SPLAT_NODE: {
- const pm_assoc_splat_node_t *splat = (const pm_assoc_splat_node_t *) cast->rest;
- ADD_INSN(ret, &line.node, dup);
- pm_compile_pattern_match(iseq, scope_node, splat->value, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1);
- break;
- }
- default:
- rb_bug("unreachable");
- break;
- }
- }
-
- ADD_INSN(ret, &line.node, pop);
- ADD_INSNL(ret, &line.node, jump, matched_label);
- ADD_INSN(ret, &line.node, putnil);
-
- ADD_LABEL(ret, type_error_label);
- ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, &line.node, putobject, rb_eTypeError);
- ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
- ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(2));
- ADD_INSN(ret, &line.node, pop);
-
- ADD_LABEL(ret, match_failed_label);
- ADD_INSN(ret, &line.node, pop);
- ADD_INSNL(ret, &line.node, jump, unmatched_label);
- break;
- }
- case PM_CAPTURE_PATTERN_NODE: {
- // Capture patterns allow you to pattern match against an element in a
- // pattern and also capture the value into a local variable. This looks
- // like:
- //
- // [1] => [Integer => foo]
- //
- // In this case the `Integer => foo` will be represented by a
- // CapturePatternNode, which has both a value (the pattern to match
- // against) and a target (the place to write the variable into).
- const pm_capture_pattern_node_t *cast = (const pm_capture_pattern_node_t *) node;
-
- LABEL *match_failed_label = NEW_LABEL(line.lineno);
-
- ADD_INSN(ret, &line.node, dup);
- CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index + 1));
- CHECK(pm_compile_pattern(iseq, scope_node, cast->target, ret, src, matched_label, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index));
- ADD_INSN(ret, &line.node, putnil);
-
- ADD_LABEL(ret, match_failed_label);
- ADD_INSN(ret, &line.node, pop);
- ADD_INSNL(ret, &line.node, jump, unmatched_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, &line.node, index, (int) cast->depth);
- ADD_INSNL(ret, &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(line.lineno);
- LABEL *unmatched_left_label = NEW_LABEL(line.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.
- ADD_INSN(ret, &line.node, dup);
- CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, src, matched_left_label, unmatched_left_label, in_single_pattern, true, true, base_index + 1));
-
- // 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);
- ADD_INSN(ret, &line.node, pop);
- ADD_INSNL(ret, &line.node, jump, matched_label);
- ADD_INSN(ret, &line.node, 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);
- CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, src, matched_label, unmatched_label, in_single_pattern, true, true, base_index));
- 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);
- if (in_single_pattern) {
- ADD_INSN1(ret, &line.node, dupn, INT2FIX(2));
- }
-
- ADD_INSN1(ret, &line.node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
-
- if (in_single_pattern) {
- pm_compile_pattern_eqq_error(iseq, scope_node, node, ret, base_index + 2);
- }
-
- ADD_INSNL(ret, &line.node, branchif, matched_label);
- ADD_INSNL(ret, &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;
- CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, src, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, true, base_index));
- 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;
- CHECK(pm_compile_pattern(iseq, scope_node, cast->expression, ret, src, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, true, base_index));
- break;
- }
- case PM_IF_NODE:
- case PM_UNLESS_NODE: {
- // If and unless nodes can show up here as guards on `in` clauses. This
- // looks like:
- //
- // case foo
- // in bar if baz?
- // qux
- // end
- //
- // Because we know they're in the modifier form and they can't have any
- // variation on this pattern, we compile them differently (more simply)
- // here than we would in the normal compilation path.
- const pm_node_t *predicate;
- const pm_node_t *statement;
-
- if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
- const pm_if_node_t *cast = (const pm_if_node_t *) node;
- predicate = cast->predicate;
-
- assert(cast->statements != NULL && cast->statements->body.size == 1);
- statement = cast->statements->body.nodes[0];
- } else {
- const pm_unless_node_t *cast = (const pm_unless_node_t *) node;
- predicate = cast->predicate;
-
- assert(cast->statements != NULL && cast->statements->body.size == 1);
- statement = cast->statements->body.nodes[0];
- }
-
- CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, src, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
- PM_COMPILE_NOT_POPPED(predicate);
-
- if (in_single_pattern) {
- LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
-
- ADD_INSN(ret, &line.node, dup);
- if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
- ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
- } else {
- ADD_INSNL(ret, &line.node, branchunless, match_succeeded_label);
- }
-
- ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("guard clause does not return true"));
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
- ADD_INSN1(ret, &line.node, putobject, Qfalse);
- ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
-
- ADD_INSN(ret, &line.node, pop);
- ADD_INSN(ret, &line.node, pop);
-
- ADD_LABEL(ret, match_succeeded_label);
- }
-
- if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
- ADD_INSNL(ret, &line.node, branchunless, unmatched_label);
- } else {
- ADD_INSNL(ret, &line.node, branchif, unmatched_label);
- }
-
- ADD_INSNL(ret, &line.node, jump, matched_label);
- 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;
-}
-
-#undef PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE
-#undef PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING
-#undef PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P
-#undef PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE
-#undef PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY
-
-// 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;
- scope->local_depth_offset = 0;
- scope->local_table_for_iseq_size = 0;
-
- if (previous) {
- scope->constants = previous->constants;
- scope->local_depth_offset = previous->local_depth_offset;
- }
- 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;
- scope->body = cast->body;
- scope->locals = cast->locals;
- scope->local_depth_offset = 0;
- scope->parameters = cast->parameters;
- 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 = (pm_node_t *)cast->parameters;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_ENSURE_NODE: {
- scope->body = (pm_node_t *)node;
- scope->local_depth_offset += 1;
- break;
- }
- case PM_FOR_NODE: {
- pm_for_node_t *cast = (pm_for_node_t *)node;
- scope->body = (pm_node_t *)cast->statements;
- scope->local_depth_offset += 1;
- break;
- }
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
- RUBY_ASSERT(node->flags & PM_REGULAR_EXPRESSION_FLAGS_ONCE);
- scope->body = (pm_node_t *)node;
- scope->local_depth_offset += 1;
- break;
- }
- case PM_LAMBDA_NODE: {
- pm_lambda_node_t *cast = (pm_lambda_node_t *) node;
- scope->parameters = cast->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;
- scope->local_depth_offset += 2;
- 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_RESCUE_NODE: {
- pm_rescue_node_t *cast = (pm_rescue_node_t *)node;
- scope->body = (pm_node_t *)cast->statements;
- scope->local_depth_offset += 1;
- break;
- }
- case PM_RESCUE_MODIFIER_NODE: {
- pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *)node;
- scope->body = (pm_node_t *)cast->rescue_expression;
- scope->local_depth_offset += 1;
- 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;
- }
-}
-
-static void pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, ID method_id, LABEL *start);
-
-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, bool explicit_receiver)
-{
- // in_condition is the same as compile.c's needstr
- enum defined_type dtype = DEFINED_NOT_DEFINED;
- switch (PM_NODE_TYPE(node)) {
- case PM_ARGUMENTS_NODE: {
- const pm_arguments_node_t *cast = (pm_arguments_node_t *) node;
- const pm_node_list_t *arguments = &cast->arguments;
- for (size_t idx = 0; idx < arguments->size; idx++) {
- const pm_node_t *argument = arguments->nodes[idx];
- pm_compile_defined_expr0(iseq, argument, ret, src, popped, scope_node, dummy_line_node, lineno, in_condition, lfinish, explicit_receiver);
-
- if (!lfinish[1]) {
- lfinish[1] = NEW_LABEL(lineno);
- }
- ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
- }
- dtype = DEFINED_TRUE;
- break;
- }
- case PM_NIL_NODE:
- dtype = DEFINED_NIL;
- break;
- case PM_PARENTHESES_NODE: {
- pm_parentheses_node_t *parentheses_node = (pm_parentheses_node_t *) node;
-
- if (parentheses_node->body == NULL) {
- dtype = DEFINED_NIL;
- } else {
- dtype = DEFINED_EXPR;
- }
- 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;
- if (!(array_node->base.flags & PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT)) {
- 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, false);
- if (!lfinish[1]) {
- lfinish[1] = NEW_LABEL(lineno);
- }
- ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
- }
- }
- }
- case PM_AND_NODE:
- case PM_FLOAT_NODE:
- case PM_HASH_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INTEGER_NODE:
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
- case PM_INTERPOLATED_STRING_NODE:
- case PM_KEYWORD_HASH_NODE:
- case PM_LAMBDA_NODE:
- case PM_MATCH_PREDICATE_NODE:
- case PM_OR_NODE:
- case PM_RANGE_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_SOURCE_ENCODING_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- case PM_X_STRING_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_BACK_REFERENCE_READ_NODE: {
- char *char_ptr = (char *)(node->location.start) + 1;
- ID backref_val = INT2FIX(rb_intern2(char_ptr, 1)) << 1 | 1;
-
- PM_PUTNIL;
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_REF),
- backref_val,
- PUSH_VAL(DEFINED_GVAR));
-
- return;
- }
- case PM_NUMBERED_REFERENCE_READ_NODE: {
- uint32_t reference_number = ((pm_numbered_reference_read_node_t *)node)->number;
-
- PM_PUTNIL;
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_REF),
- INT2FIX(reference_number << 1),
- PUSH_VAL(DEFINED_GVAR));
-
- 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, false);
- 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_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);
-
- if (call_node->receiver || call_node->arguments) {
- if (!lfinish[1]) {
- lfinish[1] = NEW_LABEL(lineno);
- }
- if (!lfinish[2]) {
- lfinish[2] = NEW_LABEL(lineno);
- }
- }
-
- if (call_node->arguments) {
- pm_compile_defined_expr0(iseq, (const pm_node_t *)call_node->arguments, ret, src, popped, scope_node, dummy_line_node, lineno, true, lfinish, false);
- ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
- }
-
- if (call_node->receiver) {
- pm_compile_defined_expr0(iseq, call_node->receiver, ret, src, popped, scope_node, dummy_line_node, lineno, true, lfinish, true);
- if (PM_NODE_TYPE_P(call_node->receiver, PM_CALL_NODE)) {
- ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[2]);
- ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
- pm_compile_call(iseq, (const pm_call_node_t *)call_node->receiver, ret, src, popped, scope_node, method_id, NULL);
- }
- else {
- ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
- PM_COMPILE(call_node->receiver);
- }
-
- if (explicit_receiver) {
- PM_DUP;
- }
-
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_METHOD), rb_id2sym(method_id), PUSH_VAL(DEFINED_METHOD));
- }
- else {
- PM_PUTSELF;
- if (explicit_receiver) {
- PM_DUP;
- }
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_FUNC), rb_id2sym(method_id), PUSH_VAL(DEFINED_METHOD));
- }
- 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:
- rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- }
-
- assert(dtype != DEFINED_NOT_DEFINED);
-
- ADD_INSN1(ret, &dummy_line_node, putobject, PUSH_VAL(dtype));
-#undef PUSH_VAL
-}
-
-static void
-pm_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, bool explicit_receiver)
-{
- LINK_ELEMENT *lcur = ret->last;
-
- pm_compile_defined_expr0(iseq, node, ret, src, popped, scope_node, dummy_line_node, lineno, in_condition, lfinish, false);
-
- if (lfinish[1]) {
- LABEL *lstart = NEW_LABEL(lineno);
- LABEL *lend = NEW_LABEL(lineno);
-
- struct rb_iseq_new_with_callback_callback_func *ifunc =
- rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
-
- const rb_iseq_t *rescue = new_child_iseq_with_callback(iseq, ifunc,
- rb_str_concat(rb_str_new2("defined guard in "),
- ISEQ_BODY(iseq)->location.label),
- iseq, ISEQ_TYPE_RESCUE, 0);
-
- lstart->rescued = LABEL_RESCUE_BEG;
- lend->rescued = LABEL_RESCUE_END;
-
- APPEND_LABEL(ret, lcur, lstart);
- ADD_LABEL(ret, lend);
- ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
- }
-}
-
-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[3];
- LINK_ELEMENT *last = ret->last;
-
- lfinish[0] = NEW_LABEL(lineno);
- lfinish[1] = 0;
- lfinish[2] = 0;
-
- if (!popped) {
- pm_defined_expr(iseq, node, ret, src, popped, scope_node, dummy_line_node, lineno, in_condition, lfinish, false);
- }
-
- if (lfinish[1]) {
- ELEM_INSERT_NEXT(last, &new_insn_body(iseq, &dummy_line_node, BIN(putnil), 0)->link);
- PM_SWAP;
- if (lfinish[2]) {
- ADD_LABEL(ret, lfinish[2]);
- }
- PM_POP;
- ADD_LABEL(ret, lfinish[1]);
-
- }
- ADD_LABEL(ret, lfinish[0]);
-}
-
-static void
-pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, ID method_id, LABEL *start)
-{
- 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, ((pm_node_t *)call_node)->location.start).line;
- NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
- LABEL *else_label = NEW_LABEL(lineno);
- LABEL *end_label = NEW_LABEL(lineno);
-
- pm_node_t *pm_node = (pm_node_t *)call_node;
-
- if (call_node->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) {
- PM_DUP;
- ADD_INSNL(ret, &dummy_line_node, branchnil, else_label);
- }
-
- int flags = 0;
- struct rb_callinfo_kwarg *kw_arg = NULL;
-
- 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);
- if (ISEQ_BODY(block_iseq)->catch_table) {
- ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, start, end_label, block_iseq, end_label);
- }
- ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
- }
- else {
- if (pm_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 || PM_NODE_TYPE_P(call_node->receiver, PM_SELF_NODE)) {
- flags |= VM_CALL_FCALL;
- }
-
- if (pm_node->flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) {
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(orig_argc + 1));
- }
- ADD_SEND_R(ret, &dummy_line_node, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
- PM_POP_UNLESS_POPPED;
- }
- else {
- ADD_SEND_R(ret, &dummy_line_node, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
- }
-
- if (call_node->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) {
- ADD_INSNL(ret, &dummy_line_node, jump, end_label);
- ADD_LABEL(ret, else_label);
- }
- ADD_LABEL(ret, end_label);
-
- PM_POP_IF_POPPED;
-}
-
-// This is exactly the same as add_ensure_iseq, except it compiled
-// the node as a Prism node, and not a CRuby node
-static void
-pm_add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return, const uint8_t *src, pm_scope_node_t *scope_node)
-{
- assert(can_add_ensure_iseq(iseq));
-
- struct iseq_compile_data_ensure_node_stack *enlp =
- ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
- struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
- DECL_ANCHOR(ensure);
-
- INIT_ANCHOR(ensure);
- while (enlp) {
- if (enlp->erange != NULL) {
- DECL_ANCHOR(ensure_part);
- LABEL *lstart = NEW_LABEL(0);
- LABEL *lend = NEW_LABEL(0);
- INIT_ANCHOR(ensure_part);
-
- add_ensure_range(iseq, enlp->erange, lstart, lend);
-
- ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
- ADD_LABEL(ensure_part, lstart);
- bool popped = true;
- PM_COMPILE_INTO_ANCHOR(ensure_part, (pm_node_t *)enlp->ensure_node);
- ADD_LABEL(ensure_part, lend);
- ADD_SEQ(ensure, ensure_part);
- }
- else {
- if (!is_return) {
- break;
- }
- }
- enlp = enlp->prev;
- }
- ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
- ADD_SEQ(ret, ensure);
-}
-
-static void
-pm_insert_local_index(pm_constant_id_t constant_id, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node)
-{
- ID local = pm_constant_id_lookup(scope_node, constant_id);
- local_table_for_iseq->ids[local_index] = local;
- st_insert(index_lookup_table, constant_id, local_index);
-}
-
-static int
-pm_compile_multi_assign_params(pm_multi_target_node_t *multi, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node, int local_index)
-{
- for (size_t m = 0; m < multi->lefts.size; m++) {
- pm_node_t *multi_node = multi->lefts.nodes[m];
-
- switch (PM_NODE_TYPE(multi_node)) {
- case PM_REQUIRED_PARAMETER_NODE: {
- pm_required_parameter_node_t *req = (pm_required_parameter_node_t *)multi_node;
- pm_insert_local_index(req->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
- break;
- }
- case PM_MULTI_TARGET_NODE: {
- local_index = pm_compile_multi_assign_params((pm_multi_target_node_t *)multi_node, index_lookup_table, local_table_for_iseq, scope_node, local_index);
- break;
- }
- default: {
- rb_bug("Parameter within a MultiTargetNode isn't allowed");
- }
- }
- }
-
- if (multi->rest && PM_NODE_TYPE_P(multi->rest, PM_SPLAT_NODE)) {
- pm_splat_node_t *rest = (pm_splat_node_t *)multi->rest;
- if (rest->expression && PM_NODE_TYPE_P(rest->expression, PM_REQUIRED_PARAMETER_NODE)) {
- pm_required_parameter_node_t *req = (pm_required_parameter_node_t *)rest->expression;
- pm_insert_local_index(req->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
- }
- }
-
- for (size_t m = 0; m < multi->rights.size; m++) {
- pm_node_t *multi_node = multi->rights.nodes[m];
-
- switch (PM_NODE_TYPE(multi_node)) {
- case PM_REQUIRED_PARAMETER_NODE: {
- pm_required_parameter_node_t *req = (pm_required_parameter_node_t *)multi_node;
- pm_insert_local_index(req->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
- break;
- }
- case PM_MULTI_TARGET_NODE: {
- local_index = pm_compile_multi_assign_params((pm_multi_target_node_t *)multi_node, index_lookup_table, local_table_for_iseq, scope_node, local_index);
- break;
- }
- default: {
- rb_bug("Parameter within a MultiTargetNode isn't allowed");
- }
- }
- }
-
- return local_index;
-}
-
-/*
- * 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);
-
- if (node->flags & PM_NODE_FLAG_NEWLINE &&
- ISEQ_COMPILE_DATA(iseq)->last_line != lineno) {
- int event = RUBY_EVENT_LINE;
-
- ISEQ_COMPILE_DATA(iseq)->last_line = lineno;
- if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
- event |= RUBY_EVENT_COVERAGE_LINE;
- }
- ADD_TRACE(ret, event);
- }
-
- 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: {
- // These are ArgumentsNodes that are not compiled directly by their
- // parent call nodes, used in the cases of NextNodes, ReturnNodes
- // and BreakNodes
- 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]);
- }
- if (node_list.size > 1) {
- ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(node_list.size));
- }
- 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) {
- pm_array_node_t *cast = (pm_array_node_t *) node;
- if (cast->elements.size) {
- 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 {
- ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(0));
- }
- }
- } 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;
-
- // In the case that there is a splat node within the array,
- // the array gets compiled slightly differently.
- if (node->flags & PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT) {
- if (elements->size == 1) {
- // If the only nodes is a SplatNode, we never
- // need to emit the newarray or concatarray
- // instructions
- PM_COMPILE_NOT_POPPED(elements->nodes[0]);
- }
- else {
- // We treat all sequences of non-splat elements as their
- // own arrays, followed by a newarray, and then continually
- // concat the arrays with the SplatNodes
- int new_array_size = 0;
- bool need_to_concat_array = false;
- for (size_t index = 0; index < elements->size; index++) {
- pm_node_t *array_element = elements->nodes[index];
- if (PM_NODE_TYPE_P(array_element, PM_SPLAT_NODE)) {
- pm_splat_node_t *splat_element = (pm_splat_node_t *)array_element;
-
- // If we already have non-splat elements, we need to emit a newarray
- // instruction
- if (new_array_size) {
- ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(new_array_size));
-
- // We don't want to emit a concat array in the case where
- // we're seeing our first splat, and already have elements
- if (need_to_concat_array) {
- ADD_INSN(ret, &dummy_line_node, concatarray);
- }
-
- new_array_size = 0;
- }
-
- PM_COMPILE_NOT_POPPED(splat_element->expression);
-
- if (index > 0) {
- ADD_INSN(ret, &dummy_line_node, concatarray);
- }
- else {
- // If this is the first element, we need to splatarray
- ADD_INSN1(ret, &dummy_line_node, splatarray, Qtrue);
- }
-
- need_to_concat_array = true;
- }
- else {
- new_array_size++;
- PM_COMPILE_NOT_POPPED(array_element);
- }
- }
-
- if (new_array_size) {
- ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(new_array_size));
- if (need_to_concat_array) {
- ADD_INSN(ret, &dummy_line_node, concatarray);
- }
- }
- }
-
- PM_POP_IF_POPPED;
- }
- else {
- 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);
- LABEL *lcont = NEW_LABEL(lineno);
-
-
- if (begin_node->rescue_clause) {
- pm_scope_node_t rescue_scope_node;
- pm_scope_node_init((pm_node_t *)begin_node->rescue_clause, &rescue_scope_node, scope_node, parser);
-
- rb_iseq_t *rescue_iseq = NEW_CHILD_ISEQ(rescue_scope_node,
- rb_str_concat(rb_str_new2("rescue in"),
- ISEQ_BODY(iseq)->location.label),
- ISEQ_TYPE_RESCUE, 1);
- lstart->rescued = LABEL_RESCUE_BEG;
- lend->rescued = LABEL_RESCUE_END;
- ADD_LABEL(ret, lstart);
- bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
- ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
- if (begin_node->statements) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)begin_node->statements);
- }
- else {
- PM_PUTNIL;
- }
- ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
-
- if (begin_node->else_clause) {
- PM_POP_UNLESS_POPPED;
- PM_COMPILE((pm_node_t *)begin_node->else_clause);
- }
-
- ADD_LABEL(ret, lend);
- PM_NOP;
- ADD_LABEL(ret, lcont);
-
- PM_POP_IF_POPPED;
- ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue_iseq, lcont);
- ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
- }
- if (begin_node->ensure_clause) {
- LABEL *estart = NEW_LABEL(lineno);
- LABEL *eend = NEW_LABEL(lineno);
- LABEL *econt = NEW_LABEL(lineno);
- ADD_LABEL(ret, estart);
- if (!begin_node->rescue_clause) {
- if (begin_node->statements) {
- PM_COMPILE((pm_node_t *)begin_node->statements);
- }
- else {
- PM_PUTNIL_UNLESS_POPPED;
- }
- }
- ADD_LABEL(ret, eend);
- if (!popped) {
- PM_NOP;
- }
- pm_statements_node_t *statements = begin_node->ensure_clause->statements;
- if (statements) {
- PM_COMPILE((pm_node_t *)statements);
- ADD_LABEL(ret, econt);
- PM_POP_UNLESS_POPPED;
- }
-
- struct ensure_range er;
- struct iseq_compile_data_ensure_node_stack enl;
- struct ensure_range *erange;
-
- er.begin = estart;
- er.end = eend;
- er.next = 0;
- push_ensure_entry(iseq, &enl, &er, (void *)begin_node->ensure_clause);
-
- 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);
- ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq;
-
-
- erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
- if (estart->link.next != &eend->link) {
- while (erange) {
- ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end, child_iseq, econt);
- erange = erange->next;
- }
- }
- }
-
- if (!begin_node->rescue_clause && !begin_node->ensure_clause) {
- 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);
- }
- 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;
- unsigned long throw_flag = 0;
- if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
- /* while/until */
- LABEL *splabel = NEW_LABEL(0);
- ADD_LABEL(ret, splabel);
- ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
- 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);
- ADD_ADJUST_RESTORE(ret, splabel);
-
- PM_PUTNIL_UNLESS_POPPED;
- } else {
- const rb_iseq_t *ip = iseq;
-
- while (ip) {
- if (!ISEQ_COMPILE_DATA(ip)) {
- ip = 0;
- break;
- }
-
- if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
- throw_flag = VM_THROW_NO_ESCAPE_FLAG;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
- throw_flag = 0;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
- COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
- rb_bug("Can't escape from eval with break");
- }
- else {
- ip = ISEQ_BODY(ip)->parent_iseq;
- continue;
- }
-
- /* escape from block */
- if (break_node->arguments) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)break_node->arguments);
- }
- else {
- PM_PUTNIL;
- }
-
- ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
- PM_POP_IF_POPPED;
-
- return;
- }
- COMPILE_ERROR(ERROR_ARGS "Invalid break");
- rb_bug("Invalid break");
- }
- return;
- }
- case PM_CALL_NODE: {
- pm_call_node_t *call_node = (pm_call_node_t *) node;
- LABEL *start = NEW_LABEL(lineno);
-
- if (call_node->block) {
- ADD_LABEL(ret, start);
- }
-
- ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
- if (node->flags & PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) {
- if (!popped) {
- PM_PUTNIL;
- }
- }
-
- if (call_node->receiver == NULL) {
- PM_PUTSELF;
- } else {
- PM_COMPILE_NOT_POPPED(call_node->receiver);
- }
-
- pm_compile_call(iseq, call_node, ret, src, popped, scope_node, method_id, start);
- return;
- }
- case PM_CALL_AND_WRITE_NODE: {
- pm_call_and_write_node_t *call_and_write_node = (pm_call_and_write_node_t*) node;
-
- bool safe_nav = node->flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION;
-
- 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, safe_nav, 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;
- bool safe_nav = node->flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION;
-
- 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, safe_nav, 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) {
- PM_COMPILE((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_CASE_MATCH_NODE: {
- // If you use the `case` keyword to create a case match node, it will
- // match against all of the `in` clauses until it finds one that
- // matches. If it doesn't find one, it can optionally fall back to an
- // `else` clause. If none is present and a match wasn't found, it will
- // raise an appropriate error.
- const pm_case_match_node_t *cast = (const pm_case_match_node_t *) node;
-
- // This is the anchor that we will compile the bodies of the various
- // `in` nodes into. We'll make sure that the patterns that are compiled
- // jump into the correct spots within this anchor.
- DECL_ANCHOR(body_seq);
- INIT_ANCHOR(body_seq);
-
- // This is the anchor that we will compile the patterns of the various
- // `in` nodes into. If a match is found, they will need to jump into the
- // body_seq anchor to the correct spot.
- DECL_ANCHOR(cond_seq);
- INIT_ANCHOR(cond_seq);
-
- // This label is used to indicate the end of the entire node. It is
- // jumped to after the entire stack is cleaned up.
- LABEL *end_label = NEW_LABEL(lineno);
-
- // This label is used as the fallback for the case match. If no match is
- // found, then we jump to this label. This is either an `else` clause or
- // an error handler.
- LABEL *else_label = NEW_LABEL(lineno);
-
- // We're going to use this to uniquely identify each branch so that we
- // can track coverage information.
- int branch_id = 0;
- // VALUE branches = 0;
-
- // If there is only one pattern, then the behavior changes a bit. It
- // effectively gets treated as a match required node (this is how it is
- // represented in the other parser).
- bool in_single_pattern = cast->consequent == NULL && cast->conditions.size == 1;
-
- // First, we're going to push a bunch of stuff onto the stack that is
- // going to serve as our scratch space.
- if (in_single_pattern) {
- ADD_INSN(ret, &dummy_line_node, putnil); // key error key
- ADD_INSN(ret, &dummy_line_node, putnil); // key error matchee
- ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse); // key error?
- ADD_INSN(ret, &dummy_line_node, putnil); // error string
- }
-
- // Now we're going to compile the value to match against.
- ADD_INSN(ret, &dummy_line_node, putnil); // deconstruct cache
- PM_COMPILE_NOT_POPPED(cast->predicate);
-
- // Next, we'll loop through every in clause and compile its body into
- // the body_seq anchor and its pattern into the cond_seq anchor. We'll
- // make sure the pattern knows how to jump correctly into the body if it
- // finds a match.
- for (size_t index = 0; index < cast->conditions.size; index++) {
- const pm_node_t *condition = cast->conditions.nodes[index];
- assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
-
- const pm_in_node_t *in_node = (const pm_in_node_t *) condition;
-
- pm_line_node_t in_line;
- pm_line_node(&in_line, scope_node, (const pm_node_t *) in_node);
-
- pm_line_node_t pattern_line;
- pm_line_node(&pattern_line, scope_node, (const pm_node_t *) in_node->pattern);
-
- if (branch_id) {
- ADD_INSN(body_seq, &in_line.node, putnil);
- }
-
- LABEL *body_label = NEW_LABEL(in_line.lineno);
- ADD_LABEL(body_seq, body_label);
- ADD_INSN1(body_seq, &in_line.node, adjuststack, INT2FIX(in_single_pattern ? 6 : 2));
-
- // TODO: We need to come back to this and enable trace branch
- // coverage. At the moment we can't call this function because it
- // accepts a NODE* and not a pm_node_t*.
- // add_trace_branch_coverage(iseq, body_seq, in_node->statements || in, branch_id++, "in", branches);
-
- branch_id++;
- if (in_node->statements != NULL) {
- PM_COMPILE_INTO_ANCHOR(body_seq, (const pm_node_t *) in_node->statements);
- } else if (!popped) {
- ADD_INSN(body_seq, &in_line.node, putnil);
- }
-
- ADD_INSNL(body_seq, &in_line.node, jump, end_label);
- LABEL *next_pattern_label = NEW_LABEL(pattern_line.lineno);
-
- ADD_INSN(cond_seq, &pattern_line.node, dup);
- pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, src, body_label, next_pattern_label, in_single_pattern, false, true, 2);
- ADD_LABEL(cond_seq, next_pattern_label);
- LABEL_UNREMOVABLE(next_pattern_label);
- }
-
- if (cast->consequent != NULL) {
- // If we have an `else` clause, then this becomes our fallback (and
- // there is no need to compile in code to potentially raise an
- // error).
- const pm_else_node_t *else_node = (const pm_else_node_t *) cast->consequent;
-
- ADD_LABEL(cond_seq, else_label);
- ADD_INSN(cond_seq, &dummy_line_node, pop);
- ADD_INSN(cond_seq, &dummy_line_node, pop);
-
- // TODO: trace branch coverage
- // add_trace_branch_coverage(iseq, cond_seq, cast->consequent, branch_id, "else", branches);
-
- if (else_node->statements != NULL) {
- PM_COMPILE_INTO_ANCHOR(cond_seq, (const pm_node_t *) else_node->statements);
- } else if (!popped) {
- ADD_INSN(cond_seq, &dummy_line_node, putnil);
- }
-
- ADD_INSNL(cond_seq, &dummy_line_node, jump, end_label);
- ADD_INSN(cond_seq, &dummy_line_node, putnil);
- if (popped) {
- ADD_INSN(cond_seq, &dummy_line_node, putnil);
- }
- } else {
- // Otherwise, if we do not have an `else` clause, we will compile in
- // the code to handle raising an appropriate error.
- ADD_LABEL(cond_seq, else_label);
-
- // TODO: trace branch coverage
- // add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
-
- if (in_single_pattern) {
- pm_compile_pattern_error_handler(iseq, scope_node, node, cond_seq, src, end_label, popped);
- } else {
- ADD_INSN1(cond_seq, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(cond_seq, &dummy_line_node, putobject, rb_eNoMatchingPatternError);
- ADD_INSN1(cond_seq, &dummy_line_node, topn, INT2FIX(2));
- ADD_SEND(cond_seq, &dummy_line_node, id_core_raise, INT2FIX(2));
-
- ADD_INSN1(cond_seq, &dummy_line_node, adjuststack, INT2FIX(3));
- if (!popped) ADD_INSN(cond_seq, &dummy_line_node, putnil);
- ADD_INSNL(cond_seq, &dummy_line_node, jump, end_label);
- ADD_INSN1(cond_seq, &dummy_line_node, dupn, INT2FIX(1));
- if (popped) ADD_INSN(cond_seq, &dummy_line_node, putnil);
- }
- }
-
- // At the end of all of this compilation, we will add the code for the
- // conditions first, then the various bodies, then mark the end of the
- // entire sequence with the end label.
- ADD_SEQ(ret, cond_seq);
- ADD_SEQ(ret, body_seq);
- 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);
- LABEL *start_label = NEW_LABEL(lineno);
-
- ADD_INSN(ret, &dummy_line_node, putnil);
- ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CVAR),
- ID2SYM(pm_constant_id_lookup(scope_node, class_variable_or_write_node->name)), Qtrue);
-
- ADD_INSNL(ret, &dummy_line_node, branchunless, start_label);
-
- 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;
- ADD_LABEL(ret, start_label);
-
- 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;
- if (target->parent) {
- PM_COMPILE_NOT_POPPED(target->parent);
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
- }
-
- 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;
- if (target->parent) {
- PM_COMPILE_NOT_POPPED(target->parent);
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
- }
-
- 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;
- if (target->parent) {
- PM_COMPILE_NOT_POPPED(target->parent);
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
- }
-
- 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_ENSURE_NODE: {
- pm_ensure_node_t *ensure_node = (pm_ensure_node_t *)node;
-
- LABEL *start = NEW_LABEL(lineno);
- LABEL *end = NEW_LABEL(lineno);
- ADD_LABEL(ret, start);
- if (ensure_node->statements) {
- ISEQ_COMPILE_DATA(iseq)->end_label = end;
- PM_COMPILE((pm_node_t *)ensure_node->statements);
- }
- ADD_LABEL(ret, end);
- }
- 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_UNLESS_POPPED;
- }
- 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;
-
- ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
-
- 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);
-
- 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);
-
- ADD_LABEL(ret, 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);
- }
-
- DECL_ANCHOR(args);
- INIT_ANCHOR(args);
-
- struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
-
- const rb_iseq_t *local_iseq = body->local_iseq;
- const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(local_iseq);
-
- int argc = 0;
- int depth = get_lvar_level(iseq);
-
- if (local_body->param.flags.has_lead) {
- /* required arguments */
- for (int i = 0; i < local_body->param.lead_num; i++) {
- int idx = local_body->local_table_size - i;
- ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
- }
- argc += local_body->param.lead_num;
- }
-
-
- if (local_body->param.flags.has_opt) {
- /* optional arguments */
- for (int j = 0; j < local_body->param.opt_num; j++) {
- int idx = local_body->local_table_size - (argc + j);
- ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
- }
- argc += local_body->param.opt_num;
- }
-
- if (local_body->param.flags.has_rest) {
- /* rest argument */
- int idx = local_body->local_table_size - local_body->param.rest_start;
- ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
- ADD_INSN1(args, &dummy_line_node, splatarray, Qfalse);
-
- argc = local_body->param.rest_start + 1;
- flag |= VM_CALL_ARGS_SPLAT;
- }
-
- if (local_body->param.flags.has_post) {
- /* post arguments */
- int post_len = local_body->param.post_num;
- int post_start = local_body->param.post_start;
-
- int j = 0;
- for (; j < post_len; j++) {
- int idx = local_body->local_table_size - (post_start + j);
- ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
- }
-
- if (local_body->param.flags.has_rest) {
- // argc remains unchanged from rest branch
- ADD_INSN1(args, &dummy_line_node, newarray, INT2FIX(j));
- ADD_INSN (args, &dummy_line_node, concatarray);
- }
- else {
- argc = post_len + post_start;
- }
- }
-
- const struct rb_iseq_param_keyword *const local_keyword = local_body->param.keyword;
- if (local_body->param.flags.has_kw) {
- int local_size = local_body->local_table_size;
- argc++;
-
- ADD_INSN1(args, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- if (local_body->param.flags.has_kwrest) {
- int idx = local_body->local_table_size - local_keyword->rest_start;
- ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
- if (local_keyword->num > 0) {
- ADD_SEND(args, &dummy_line_node, rb_intern("dup"), INT2FIX(0));
- flag |= VM_CALL_KW_SPLAT_MUT;
- }
- }
- else {
- ADD_INSN1(args, &dummy_line_node, newhash, INT2FIX(0));
- flag |= VM_CALL_KW_SPLAT_MUT;
- }
- int i = 0;
- for (; i < local_keyword->num; ++i) {
- ID id = local_keyword->table[i];
- int idx = local_size - get_local_var_idx(local_iseq, id);
- ADD_INSN1(args, &dummy_line_node, putobject, ID2SYM(id));
- ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
- }
- ADD_SEND(args, &dummy_line_node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
- flag |= VM_CALL_KW_SPLAT;
- }
- else if (local_body->param.flags.has_kwrest) {
- int idx = local_body->local_table_size - local_keyword->rest_start;
- ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
- argc++;
- flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
- }
-
- ADD_SEQ(ret, args);
- ADD_INSN2(ret, &dummy_line_node, invokesuper, new_callinfo(iseq, 0, argc, 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_IN_NODE: {
- // In nodes are handled by the case match node directly, so we should
- // never end up hitting them through this path.
- rb_bug("Should not ever enter an in node directly");
- return;
- }
- case PM_INDEX_AND_WRITE_NODE: {
- pm_index_and_write_node_t *index_and_write_node = (pm_index_and_write_node_t *)node;
-
- pm_compile_index_and_or_write_node(true, index_and_write_node->receiver, index_and_write_node->value, index_and_write_node->arguments, index_and_write_node->block, ret, iseq, lineno, src, popped, scope_node, parser);
- return;
- }
- case PM_INDEX_OR_WRITE_NODE: {
- pm_index_or_write_node_t *index_or_write_node = (pm_index_or_write_node_t *)node;
-
- pm_compile_index_and_or_write_node(false, index_or_write_node->receiver, index_or_write_node->value, index_or_write_node->arguments, index_or_write_node->block, ret, iseq, lineno, src, popped, scope_node, parser);
- return;
- }
- case PM_INDEX_OPERATOR_WRITE_NODE: {
- pm_index_operator_write_node_t *index_operator_write_node = (pm_index_operator_write_node_t *)node;
-
- PM_PUTNIL_UNLESS_POPPED;
-
- PM_COMPILE_NOT_POPPED(index_operator_write_node->receiver);
-
- int flag = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
- int argc_int = 0;
-
- if (index_operator_write_node->arguments) {
- argc_int = pm_setup_args(index_operator_write_node->arguments, &flag, &keywords, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
- }
-
- VALUE argc = INT2FIX(argc_int);
-
- int block_offset = 0;
-
- if (index_operator_write_node->block) {
- PM_COMPILE_NOT_POPPED(index_operator_write_node->block);
- flag |= VM_CALL_ARGS_BLOCKARG;
- block_offset = 1;
- }
-
- ADD_INSN1(ret, &dummy_line_node, dupn, FIXNUM_INC(argc, 1 + block_offset));
-
- ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idAREF, argc, INT2FIX(flag));
-
- PM_COMPILE_NOT_POPPED(index_operator_write_node->value);
-
- ID method_id = pm_constant_id_lookup(scope_node, index_operator_write_node->operator);
- ADD_SEND(ret, &dummy_line_node, method_id, INT2FIX(1));
-
- pm_compile_index_write_nodes_add_send(popped, ret, iseq, dummy_line_node, argc, flag, block_offset);
-
- 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;
-
- int parts_size = (int)cast->parts.size;
- if (parts_size > 0 && !PM_NODE_TYPE_P(cast->parts.nodes[0], PM_STRING_NODE)) {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_str_new(0, 0));
- parts_size++;
- }
-
- 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(parts_size));
-
- ADD_INSN1(ret, &dummy_line_node, getglobal, rb_id2sym(idLASTLINE));
- ADD_SEND(ret, &dummy_line_node, idEqTilde, INT2NUM(1));
- PM_POP_IF_POPPED;
-
- return;
- }
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
- if (node->flags & PM_REGULAR_EXPRESSION_FLAGS_ONCE) {
- const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
- const rb_iseq_t *block_iseq = NULL;
- int ic_index = ISEQ_BODY(iseq)->ise_size++;
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((pm_node_t*)node, &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;
-
- ADD_INSN2(ret, &dummy_line_node, once, block_iseq, INT2FIX(ic_index));
-
- ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
- return;
- }
-
- pm_interpolated_regular_expression_node_t *cast = (pm_interpolated_regular_expression_node_t *) node;
-
- int parts_size = (int)cast->parts.size;
- if (cast->parts.size > 0 && !PM_NODE_TYPE_P(cast->parts.nodes[0], PM_STRING_NODE)) {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_str_new(0, 0));
- parts_size++;
- }
-
- 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(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 + scope_node->local_depth_offset;
- 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 + scope_node->local_depth_offset;
- 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 + scope_node->local_depth_offset;
- 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 + scope_node->local_depth_offset);
- }
- 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;
- int index = pm_lookup_local_index_any_scope(iseq, scope_node, constant_id);
-
- ADD_SETLOCAL(ret, &dummy_line_node, index, local_write_node->depth + scope_node->local_depth_offset);
- 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_any_scope(iseq, scope_node, constant_id);
-
- ADD_SETLOCAL(ret, &dummy_line_node, index, local_write_node->depth + scope_node->local_depth_offset);
- 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, scope_node, cast->pattern, ret, src, matched_label, unmatched_label, false, false, true, 2);
-
- // 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_REQUIRED_NODE: {
- // A match required node represents pattern matching against a single
- // pattern using the => operator. For example,
- //
- // foo => bar
- //
- // This is somewhat analogous to compiling a case match statement with a
- // single pattern. In both cases, if the pattern fails it should
- // immediately raise an error.
- const pm_match_required_node_t *cast = (const pm_match_required_node_t *) node;
-
- LABEL *matched_label = NEW_LABEL(lineno);
- LABEL *unmatched_label = NEW_LABEL(lineno);
- LABEL *done_label = NEW_LABEL(lineno);
-
- // First, we're going to push a bunch of stuff onto the stack that is
- // going to serve as our scratch space.
- ADD_INSN(ret, &dummy_line_node, putnil); // key error key
- ADD_INSN(ret, &dummy_line_node, putnil); // key error matchee
- ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse); // key error?
- ADD_INSN(ret, &dummy_line_node, putnil); // error string
- ADD_INSN(ret, &dummy_line_node, putnil); // deconstruct cache
-
- // Next we're going to compile the value expression such that it's on
- // the stack.
- PM_COMPILE_NOT_POPPED(cast->value);
-
- // Here we'll dup it so that it can be used for comparison, but also be
- // used for error handling.
- ADD_INSN(ret, &dummy_line_node, dup);
-
- // Next we'll compile the pattern. We indicate to the pm_compile_pattern
- // function that this is the only pattern that will be matched against
- // through the in_single_pattern parameter. We also indicate that the
- // value to compare against is 2 slots from the top of the stack (the
- // base_index parameter).
- pm_compile_pattern(iseq, scope_node, cast->pattern, ret, src, matched_label, unmatched_label, true, false, true, 2);
-
- // If the pattern did not match the value, then we're going to compile
- // in our error handler code. This will determine which error to raise
- // and raise it.
- ADD_LABEL(ret, unmatched_label);
- pm_compile_pattern_error_handler(iseq, scope_node, node, ret, src, done_label, popped);
-
- // If the pattern did match, we'll clean up the values we've pushed onto
- // the stack and then push nil onto the stack if it's not popped.
- ADD_LABEL(ret, matched_label);
- ADD_INSN1(ret, &dummy_line_node, adjuststack, INT2FIX(6));
- if (!popped) ADD_INSN(ret, &dummy_line_node, putnil);
- ADD_INSNL(ret, &dummy_line_node, jump, done_label);
-
- ADD_LABEL(ret, done_label);
- return;
- }
- case PM_MATCH_WRITE_NODE: {
- // Match write nodes are specialized call nodes that have a regular
- // expression with valid named capture groups on the left, the =~
- // operator, and some value on the right. The nodes themselves simply
- // wrap the call with the local variable targets that will be written
- // when the call is executed.
- pm_match_write_node_t *cast = (pm_match_write_node_t *) node;
- LABEL *fail_label = NEW_LABEL(lineno);
- LABEL *end_label = NEW_LABEL(lineno);
-
- // First, we'll compile the call so that all of its instructions are
- // present. Then we'll compile all of the local variable targets.
- PM_COMPILE_NOT_POPPED((pm_node_t *) cast->call);
-
- // Now, check if the match was successful. If it was, then we'll
- // continue on and assign local variables. Otherwise we'll skip over the
- // assignment code.
- ADD_INSN1(ret, &dummy_line_node, getglobal, rb_id2sym(idBACKREF));
- PM_DUP;
- ADD_INSNL(ret, &dummy_line_node, branchunless, fail_label);
-
- // If there's only a single local variable target, we can skip some of
- // the bookkeeping, so we'll put a special branch here.
- size_t targets_count = cast->targets.size;
-
- if (targets_count == 1) {
- pm_node_t *target = cast->targets.nodes[0];
- assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_TARGET_NODE));
-
- pm_local_variable_target_node_t *local_target = (pm_local_variable_target_node_t *) target;
- int index = pm_lookup_local_index(iseq, scope_node, local_target->name);
-
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_id2sym(pm_constant_id_lookup(scope_node, local_target->name)));
- ADD_SEND(ret, &dummy_line_node, idAREF, INT2FIX(1));
- ADD_LABEL(ret, fail_label);
- ADD_SETLOCAL(ret, &dummy_line_node, index, (int) local_target->depth);
- PM_POP_IF_POPPED;
- return;
- }
-
- // Otherwise there is more than one local variable target, so we'll need
- // to do some bookkeeping.
- for (size_t targets_index = 0; targets_index < targets_count; targets_index++) {
- pm_node_t *target = cast->targets.nodes[targets_index];
- assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_TARGET_NODE));
-
- pm_local_variable_target_node_t *local_target = (pm_local_variable_target_node_t *) target;
- int index = pm_lookup_local_index(iseq, scope_node, local_target->name);
-
- if (((size_t) targets_index) < (targets_count - 1)) {
- PM_DUP;
- }
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_id2sym(pm_constant_id_lookup(scope_node, local_target->name)));
- ADD_SEND(ret, &dummy_line_node, idAREF, INT2FIX(1));
- ADD_SETLOCAL(ret, &dummy_line_node, index, (int) local_target->depth);
- }
-
- // Since we matched successfully, now we'll jump to the end.
- ADD_INSNL(ret, &dummy_line_node, jump, end_label);
-
- // In the case that the match failed, we'll loop through each local
- // variable target and set all of them to `nil`.
- ADD_LABEL(ret, fail_label);
- PM_POP;
-
- for (size_t targets_index = 0; targets_index < targets_count; targets_index++) {
- pm_node_t *target = cast->targets.nodes[targets_index];
- assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_TARGET_NODE));
-
- pm_local_variable_target_node_t *local_target = (pm_local_variable_target_node_t *) target;
- int index = pm_lookup_local_index(iseq, scope_node, local_target->name);
-
- PM_PUTNIL;
- ADD_SETLOCAL(ret, &dummy_line_node, index, (int) local_target->depth);
- }
-
- // Finally, we can push the end label for either case.
- 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_REQUIRED_PARAMETER_NODE: {
- pm_required_parameter_node_t *required_parameter_node = (pm_required_parameter_node_t *)node;
- int index = pm_lookup_local_index(iseq, scope_node, required_parameter_node->name);
-
- ADD_SETLOCAL(ret, &dummy_line_node, index, 0);
- return;
- }
- case PM_MULTI_TARGET_NODE: {
- pm_multi_target_node_t *cast = (pm_multi_target_node_t *) node;
- bool has_rest_expression = (cast->rest &&
- PM_NODE_TYPE_P(cast->rest, PM_SPLAT_NODE) &&
- (((pm_splat_node_t *)cast->rest)->expression));
-
- if (cast->lefts.size) {
- int flag = (int) (bool) cast->rights.size || has_rest_expression;
- 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 (has_rest_expression) {
- if (cast->rights.size) {
- ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->rights.size), INT2FIX(3));
- }
- pm_node_t *expression = ((pm_splat_node_t *)cast->rest)->expression;
- PM_COMPILE_NOT_POPPED(expression);
- }
-
- if (cast->rights.size) {
- if (!has_rest_expression) {
- 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;
- size_t argc = 1;
-
- // 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, src, popped, lefts->nodes[index], ret, scope_node, pushed, false);
- }
-
- PM_COMPILE_NOT_POPPED(multi_write_node->value);
- PM_DUP_UNLESS_POPPED;
-
- pm_node_t *rest_expression = NULL;
- if (multi_write_node->rest && 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);
- rest_expression = rest_splat->expression;
- }
-
- size_t remainder = pushed;
- if (popped) remainder--;
-
- if (lefts->size) {
- ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(lefts->size), INT2FIX((int) (bool) (rights->size || rest_expression)));
- 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 if (PM_NODE_TYPE_P(considered_node, PM_INDEX_TARGET_NODE)) {
- pm_index_target_node_t *cast = (pm_index_target_node_t *)considered_node;
-
- if (cast->arguments) {
- pm_arguments_node_t *args = (pm_arguments_node_t *)cast->arguments;
- argc = args->arguments.size + 1;
- }
-
- if (argc == 1) {
- ADD_INSN(ret, &dummy_line_node, swap);
- }
- else {
- VALUE vals = INT2FIX(remainder + (lefts->size - index));
- ADD_INSN1(ret, &dummy_line_node, topn, vals);
- for (size_t i = 1; i < argc; i++) {
- ADD_INSN1(ret, &dummy_line_node, topn, vals);
- }
- ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(argc));
- }
-
- ADD_SEND(ret, &dummy_line_node, idASET, INT2FIX(argc));
- PM_POP;
- PM_POP;
- remainder -= argc;
-
- } else if (PM_NODE_TYPE_P(considered_node, PM_CALL_TARGET_NODE)) {
- pm_call_target_node_t *cast = (pm_call_target_node_t *)considered_node;
-
- VALUE vals = INT2FIX(remainder + (lefts->size - index));
- ADD_INSN1(ret, &dummy_line_node, topn, vals);
- ADD_INSN(ret, &dummy_line_node, swap);
-
- ID method_id = pm_constant_id_lookup(scope_node, cast->name);
- ADD_SEND(ret, &dummy_line_node, method_id, INT2FIX(argc));
- PM_POP;
- remainder -= argc;
- } else {
- PM_COMPILE(lefts->nodes[index]);
- }
- }
- }
-
- if ((pushed)) {
- if (!popped) {
- ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(pushed));
- }
- for (uint8_t index = 0; index < (pushed); index++) {
- PM_POP;
- }
- }
-
- if (rights->size) {
- if (rest_expression) {
- ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(rights->size), INT2FIX(3));
- PM_COMPILE(rest_expression);
- }
- else {
- 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]);
- }
- }
- else if (rest_expression) {
- PM_COMPILE(rest_expression);
- }
-
- return;
- }
- case PM_NEXT_NODE: {
- pm_next_node_t *next_node = (pm_next_node_t *) node;
-
- if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
- LABEL *splabel = NEW_LABEL(0);
-
- ADD_LABEL(ret, splabel);
-
- if (next_node->arguments) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)next_node->arguments);
- }
- else {
- PM_PUTNIL;
- }
- pm_add_ensure_iseq(ret, iseq, 0, src, scope_node);
-
- ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
- ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
-
- ADD_ADJUST_RESTORE(ret, splabel);
- PM_PUTNIL_UNLESS_POPPED;
- }
- else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
- LABEL *splabel = NEW_LABEL(0);
-
- ADD_LABEL(ret, splabel);
- ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
-
- if (next_node->arguments) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)next_node->arguments);
- }
- else {
- PM_PUTNIL;
- }
-
- pm_add_ensure_iseq(ret, iseq, 0, src, scope_node);
- ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
- ADD_ADJUST_RESTORE(ret, splabel);
- splabel->unremovable = FALSE;
-
- PM_PUTNIL_UNLESS_POPPED;
- }
- else {
- const rb_iseq_t *ip = iseq;
-
- unsigned long throw_flag = 0;
- while (ip) {
- if (!ISEQ_COMPILE_DATA(ip)) {
- ip = 0;
- break;
- }
-
- throw_flag = VM_THROW_NO_ESCAPE_FLAG;
- if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
- /* while loop */
- break;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
- break;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
- rb_raise(rb_eArgError, "Can't escape from eval with next");
- return;
- }
-
- ip = ISEQ_BODY(ip)->parent_iseq;
- }
- if (ip != 0) {
- if (next_node->arguments) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)next_node->arguments);
- }
- else {
- PM_PUTNIL;
- }
- ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
-
- PM_POP_IF_POPPED;
- }
- else {
- rb_raise(rb_eArgError, "Invalid next");
- return;
- }
- }
-
- 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: {
- if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
- LABEL *splabel = NEW_LABEL(0);
-
- ADD_LABEL(ret, splabel);
-
- ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
-
- pm_add_ensure_iseq(ret, iseq, 0, src, scope_node);
- ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
- ADD_ADJUST_RESTORE(ret, splabel);
- PM_PUTNIL_UNLESS_POPPED;
- }
- else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
- LABEL *splabel = NEW_LABEL(0);
-
- ADD_LABEL(ret, splabel);
- pm_add_ensure_iseq(ret, iseq, 0, src, scope_node);
- ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
- ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
- ADD_ADJUST_RESTORE(ret, splabel);
-
- PM_PUTNIL_UNLESS_POPPED;
- }
- else {
- const rb_iseq_t *ip = iseq;
-
- while (ip) {
- if (!ISEQ_COMPILE_DATA(ip)) {
- ip = 0;
- break;
- }
-
- if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
- break;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
- break;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
- rb_bug("Invalid redo\n");
- }
-
- ip = ISEQ_BODY(ip)->parent_iseq;
- }
- if (ip != 0) {
- PM_PUTNIL;
- ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
-
- PM_POP_IF_POPPED;
- }
- else {
- rb_bug("Invalid redo\n");
- }
- }
- 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_RESCUE_NODE: {
- LABEL *excep_match = NEW_LABEL(lineno);
- LABEL *rescue_end = NEW_LABEL(lineno);
-
- ISEQ_COMPILE_DATA(iseq)->end_label = rescue_end;
-
- pm_rescue_node_t *rescue_node = (pm_rescue_node_t *)node;
- iseq_set_exception_local_table(iseq);
-
- pm_node_list_t exception_list = rescue_node->exceptions;
- if (exception_list.size > 0) {
- for (size_t i = 0; i < exception_list.size; i++) {
- ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
- PM_COMPILE(exception_list.nodes[i]);
- ADD_INSN1(ret, &dummy_line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
- ADD_INSN1(ret, &dummy_line_node, branchif, excep_match);
- }
- } else {
- ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_eStandardError);
- ADD_INSN1(ret, &dummy_line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
- ADD_INSN1(ret, &dummy_line_node, branchif, excep_match);
- }
- ADD_INSN1(ret, &dummy_line_node, jump, rescue_end);
-
- ADD_LABEL(ret, excep_match);
- ADD_TRACE(ret, RUBY_EVENT_RESCUE);
- if (rescue_node->reference) {
- ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
- PM_COMPILE((pm_node_t *)rescue_node->reference);
- }
-
- if (rescue_node->statements) {
- PM_COMPILE((pm_node_t *)rescue_node->statements);
- }
- else {
- PM_PUTNIL;
- }
-
- ADD_INSN(ret, &dummy_line_node, leave);
- ADD_LABEL(ret, rescue_end);
-
- if (rescue_node->consequent) {
- PM_COMPILE((pm_node_t *)rescue_node->consequent);
- } else {
- ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
- }
-
- return;
- }
- case PM_RESCUE_MODIFIER_NODE: {
- pm_scope_node_t rescue_scope_node;
- pm_rescue_modifier_node_t *rescue_node = (pm_rescue_modifier_node_t *)node;
- pm_scope_node_init((pm_node_t *)rescue_node, &rescue_scope_node, scope_node, parser);
-
- rb_iseq_t *rescue_iseq = NEW_CHILD_ISEQ(rescue_scope_node,
- rb_str_concat(rb_str_new2("rescue in"),
- ISEQ_BODY(iseq)->location.label),
- ISEQ_TYPE_RESCUE, 1);
-
- LABEL *lstart = NEW_LABEL(lineno);
- LABEL *lend = NEW_LABEL(lineno);
- LABEL *lcont = NEW_LABEL(lineno);
-
- lstart->rescued = LABEL_RESCUE_BEG;
- lend->rescued = LABEL_RESCUE_END;
- ADD_LABEL(ret, lstart);
- PM_COMPILE_NOT_POPPED((pm_node_t *)rescue_node->expression);
- ADD_LABEL(ret, lend);
- PM_NOP;
- ADD_LABEL(ret, lcont);
-
- PM_POP_IF_POPPED;
-
- ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue_iseq, lcont);
- ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
- return;
- }
- case PM_RETURN_NODE: {
- pm_arguments_node_t *arguments = ((pm_return_node_t *)node)->arguments;
-
- if (iseq) {
- enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
- LABEL *splabel = 0;
-
- const rb_iseq_t *parent_iseq = iseq;
- enum rb_iseq_type parent_type = ISEQ_BODY(parent_iseq)->type;
- while (parent_type == ISEQ_TYPE_RESCUE || parent_type == ISEQ_TYPE_ENSURE) {
- if (!(parent_iseq = ISEQ_BODY(parent_iseq)->parent_iseq)) break;
- parent_type = ISEQ_BODY(parent_iseq)->type;
- }
-
- switch (parent_type) {
- case ISEQ_TYPE_TOP:
- case ISEQ_TYPE_MAIN:
- if (arguments) {
- rb_warn("argument of top-level return is ignored");
- }
- if (parent_iseq == iseq) {
- type = ISEQ_TYPE_METHOD;
- }
- break;
- default:
- break;
- }
-
- if (type == ISEQ_TYPE_METHOD) {
- splabel = NEW_LABEL(0);
- ADD_LABEL(ret, splabel);
- ADD_ADJUST(ret, &dummy_line_node, 0);
- }
-
- if (arguments) {
- PM_COMPILE_NOT_POPPED((pm_node_t *)arguments);
- }
- else {
- PM_PUTNIL;
- }
-
- if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
- pm_add_ensure_iseq(ret, iseq, 1, src, scope_node);
- ADD_TRACE(ret, RUBY_EVENT_RETURN);
- ADD_INSN(ret, &dummy_line_node, leave);
- ADD_ADJUST_RESTORE(ret, splabel);
-
- PM_PUTNIL_UNLESS_POPPED;
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(TAG_RETURN));
- PM_POP_IF_POPPED;
- }
- }
-
- return;
- }
- case PM_RETRY_NODE: {
- if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
- PM_PUTNIL;
- ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(TAG_RETRY));
-
- PM_POP_IF_POPPED;
- } else {
- COMPILE_ERROR(ERROR_ARGS "Invalid retry");
- rb_bug("Invalid retry");
- }
- 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 = NULL;
- 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;
- pm_node_list_t *block_locals = NULL;
- pm_node_t *block_param_keyword_rest = NULL;
-
- struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
-
- if (scope_node->parameters) {
- switch (PM_NODE_TYPE(scope_node->parameters)) {
- case PM_BLOCK_PARAMETERS_NODE: {
- pm_block_parameters_node_t *block_parameters_node = (pm_block_parameters_node_t *)scope_node->parameters;
- parameters_node = block_parameters_node->parameters;
- block_locals = &block_parameters_node->locals;
- if (parameters_node) {
- block_param_keyword_rest = parameters_node->keyword_rest;
- }
- break;
- }
- case PM_PARAMETERS_NODE: {
- parameters_node = (pm_parameters_node_t *) scope_node->parameters;
- break;
- }
- case PM_NUMBERED_PARAMETERS_NODE: {
- body->param.lead_num = ((pm_numbered_parameters_node_t *) scope_node->parameters)->maximum;
- break;
- }
- default:
- rb_bug("Unexpected node type for parameters: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- }
- }
-
- struct rb_iseq_param_keyword *keyword = NULL;
-
- 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 (scope_node->parameters && PM_NODE_TYPE_P(scope_node->parameters, PM_NUMBERED_PARAMETERS_NODE)) {
- body->param.opt_num = 0;
- }
- else {
- body->param.lead_num = 0;
- body->param.opt_num = 0;
- }
-
- //********STEP 1**********
- // Goal: calculate the table size for the locals, accounting for
- // hidden variables and multi target nodes
- size_t locals_size = locals->size;
-
- // Index lookup table buffer size is only the number of the locals
- st_table *index_lookup_table = st_init_numtable();
-
- int table_size = (int) locals_size;
-
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) {
- body->param.lead_num = 1;
- table_size++;
- }
-
- if (keywords_list && keywords_list->size) {
- table_size++;
- }
-
- if (requireds_list) {
- int number_of_anonymous_locals = 0;
- for (size_t i = 0; i < requireds_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *required = requireds_list->nodes[i];
- if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
- table_size++;
- }
- else if (PM_NODE_TYPE_P(required, PM_REQUIRED_PARAMETER_NODE)) {
- if (pm_constant_id_lookup(scope_node, ((pm_required_parameter_node_t *)required)->name) == rb_intern("_")) {
- number_of_anonymous_locals++;
- }
- }
- }
-
- // For each anonymous local we also want to increase the size
- // of the locals table. Prism's locals table accounts for all
- // anonymous locals as 1, so we need to increase the table size
- // by the number of anonymous locals - 1
- if (number_of_anonymous_locals > 1) {
- table_size += (number_of_anonymous_locals - 1);
- }
- }
-
- if (posts_list) {
- for (size_t i = 0; i < posts_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *required = posts_list->nodes[i];
- if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
- table_size++;
- }
- }
- }
-
- if (block_param_keyword_rest) {
- table_size++;
- }
-
- // When we have a `...` as the keyword_rest, it's a forwarding_parameter_node and
- // we need to leave space for 2 more locals on the locals table (`*` and `&`)
- if (parameters_node && parameters_node->keyword_rest &&
- PM_NODE_TYPE_P(parameters_node->keyword_rest, PM_FORWARDING_PARAMETER_NODE)) {
- table_size += 2;
- }
-
- // We can create local_table_for_iseq with the correct size
- VALUE idtmp = 0;
- rb_ast_id_table_t *local_table_for_iseq = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
- local_table_for_iseq->size = table_size;
-
- //********END OF STEP 1**********
-
- //********STEP 2**********
- // Goal: populate iv index table as well as local table, keeping the
- // layout of the local table consistent with the layout of the
- // stack when calling the method
- //
- // Do a first pass on all of the parameters, setting their values in
- // the local_table_for_iseq, _except_ for Multis who get a hidden
- // variable in this step, and will get their names inserted in step 3
-
- // local_index is a cursor that keeps track of the current
- // index into local_table_for_iseq. The local table is actually a list,
- // and the order of that list must match the order of the items pushed
- // on the stack. We need to take in to account things pushed on the
- // stack that _might not have a name_ (for example array destructuring).
- // This index helps us know which item we're dealing with and also give
- // those anonymous items temporary names (as below)
- int local_index = 0;
-
- // We will assign these values now, if applicable, and use them for
- // the ISEQs on these multis
- int required_multis_hidden_index = 0;
- int post_multis_hidden_index = 0;
-
- // Here we figure out local table indices and insert them in to the
- // index lookup table and local tables.
- //
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^^^^^^
- if (requireds_list && requireds_list->size) {
- for (size_t i = 0; i < requireds_list->size; i++, local_index++) {
- ID local;
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *required = requireds_list->nodes[i];
- switch (PM_NODE_TYPE(required)) {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^^^
- case PM_MULTI_TARGET_NODE: {
- required_multis_hidden_index = local_index;
- local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index] = local;
- break;
- }
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^
- case PM_REQUIRED_PARAMETER_NODE: {
- pm_required_parameter_node_t * param = (pm_required_parameter_node_t *)required;
-
- pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- break;
- }
- default: {
- rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- }
- }
- }
-
- body->param.lead_num = (int) requireds_list->size;
- body->param.flags.has_lead = true;
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^
- if (optionals_list && optionals_list->size) {
- body->param.opt_num = (int) optionals_list->size;
- body->param.flags.has_opt = true;
-
- for (size_t i = 0; i < optionals_list->size; i++, local_index++) {
- pm_constant_id_t name = ((pm_optional_parameter_node_t *)optionals_list->nodes[i])->name;
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- if (parameters_node && parameters_node->rest) {
- body->param.rest_start = local_index;
- // If there's a trailing comma, we'll have an implicit rest node,
- // and we don't want it to impact the rest variables on param
- if (!(PM_NODE_TYPE_P(parameters_node->rest, PM_IMPLICIT_REST_NODE))) {
- body->param.flags.has_rest = true;
- assert(body->param.rest_start != -1);
-
- pm_constant_id_t name = ((pm_rest_parameter_node_t *)parameters_node->rest)->name;
- if (name) {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- else {
- // def foo(a, (b, *c, d), e = 1, *, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^
- local_table_for_iseq->ids[local_index] = idMULT;
- }
- local_index++;
- }
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^^^^^^
- if (posts_list && posts_list->size) {
- body->param.post_num = (int) posts_list->size;
- body->param.post_start = local_index;
- body->param.flags.has_post = true;
-
- for (size_t i = 0; i < posts_list->size; i++, local_index++) {
- ID local;
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *post_node = posts_list->nodes[i];
- switch (PM_NODE_TYPE(post_node)) {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^^^
- case PM_MULTI_TARGET_NODE: {
- post_multis_hidden_index = local_index;
- local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index] = local;
- break;
- }
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^
- case PM_REQUIRED_PARAMETER_NODE: {
- pm_required_parameter_node_t * param = (pm_required_parameter_node_t *)post_node;
-
- pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- break;
- }
- default: {
- rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- }
- }
- }
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^
- // 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 = xcalloc(keywords_list->size, sizeof(ID));
-
- for (size_t i = 0; i < keywords_list->size; i++, local_index++) {
- pm_node_t *keyword_parameter_node = keywords_list->nodes[i];
- pm_constant_id_t name;
-
- switch (PM_NODE_TYPE(keyword_parameter_node)) {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^
- case PM_OPTIONAL_KEYWORD_PARAMETER_NODE: {
- pm_optional_keyword_parameter_node_t *cast = ((pm_optional_keyword_parameter_node_t *)keyword_parameter_node);
-
- pm_node_t *value = cast->value;
- name = cast->name;
-
- if (pm_static_literal_p(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))) {
-
- rb_ary_push(default_values, pm_static_literal_value(value, scope_node, parser));
- }
- else {
- rb_ary_push(default_values, complex_mark);
- }
-
- break;
- }
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- case PM_REQUIRED_KEYWORD_PARAMETER_NODE: {
- name = ((pm_required_keyword_parameter_node_t *)keyword_parameter_node)->name;
- keyword->required_num++;
- break;
- }
- default: {
- rb_bug("Unexpected keyword parameter node type");
- }
- }
-
- ID local = pm_constant_id_lookup(scope_node, name);
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- ids[i] = local;
- }
-
- keyword->bits_start = local_index;
- keyword->table = ids;
-
- 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;
-
- // Hidden local for keyword arguments
- ID local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index] = local;
- local_index++;
- }
-
- if (body->type == ISEQ_TYPE_BLOCK && local_index == 1 && requireds_list && requireds_list->size == 1) {
- body->param.flags.ambiguous_param0 = true;
- }
-
- if (parameters_node) {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^
- if (parameters_node->keyword_rest) {
- switch (PM_NODE_TYPE(parameters_node->keyword_rest)) {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **nil, &n)
- // ^^^^^
- case PM_NO_KEYWORDS_PARAMETER_NODE: {
-
- body->param.flags.accepts_no_kwarg = true;
- break;
- }
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^
- case PM_KEYWORD_REST_PARAMETER_NODE: {
- pm_keyword_rest_parameter_node_t *kw_rest_node = (pm_keyword_rest_parameter_node_t *)parameters_node->keyword_rest;
- if (!body->param.flags.has_kw) {
- body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
- }
-
- keyword->rest_start = local_index;
- body->param.flags.has_kwrest = true;
-
- pm_constant_id_t constant_id = kw_rest_node->name;
- if (constant_id) {
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- else {
- local_table_for_iseq->ids[local_index] = idPow;
- }
- local_index++;
- break;
- }
- // def foo(...)
- // ^^^
- case PM_FORWARDING_PARAMETER_NODE: {
- body->param.rest_start = local_index;
- body->param.flags.has_rest = true;
- ID local = idMULT;
- local_table_for_iseq->ids[local_index] = local;
- local_index++;
-
- body->param.block_start = local_index;
- body->param.flags.has_block = true;
- local = idAnd;
- local_table_for_iseq->ids[local_index] = local;
- local_index++;
-
- local = idDot3;
- local_table_for_iseq->ids[local_index] = local;
- local_index++;
- break;
- }
- default: {
- rb_raise(rb_eArgError, "node type %s not expected as keyword_rest", pm_node_type_to_str(PM_NODE_TYPE(parameters_node->keyword_rest)));
- }
- }
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- if (parameters_node->block) {
- body->param.block_start = local_index;
- body->param.flags.has_block = true;
-
- pm_constant_id_t name = ((pm_block_parameter_node_t *)parameters_node->block)->name;
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
- }
- }
-
- //********END OF STEP 2**********
- // The local table is now consistent with expected
- // stack layout
-
- // If there's only one required element in the parameters
- // CRuby needs to recognize it as an ambiguous parameter
-
- //********STEP 3**********
- // Goal: fill in the names of the parameters in MultiTargetNodes
- //
- // Go through requireds again to set the multis
-
- if (requireds_list && requireds_list->size) {
- for (size_t i = 0; i < requireds_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *required = requireds_list->nodes[i];
- if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
- local_index = pm_compile_multi_assign_params((pm_multi_target_node_t *)required, index_lookup_table, local_table_for_iseq, scope_node, local_index);
- }
- }
- }
-
- // Go through posts again to set the multis
- if (posts_list && posts_list->size) {
- for (size_t i = 0; i < posts_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *post= posts_list->nodes[i];
- if (PM_NODE_TYPE_P(post, PM_MULTI_TARGET_NODE)) {
- local_index = pm_compile_multi_assign_params((pm_multi_target_node_t *)post, index_lookup_table, local_table_for_iseq, scope_node, local_index);
- }
- }
- }
-
- // Set any anonymous locals for the for node
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) {
- ID local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index] = local;
- local_index++;
- }
-
- // Fill in any NumberedParameters, if they exist
- if (scope_node->parameters && PM_NODE_TYPE_P(scope_node->parameters, PM_NUMBERED_PARAMETERS_NODE)) {
- int maximum = ((pm_numbered_parameters_node_t *)scope_node->parameters)->maximum;
- for (int i = 0; i < maximum; i++, local_index++) {
- pm_constant_id_t constant_id = locals->ids[i];
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- }
- //********END OF STEP 3**********
-
- //********STEP 4**********
- // Goal: fill in the method body locals
- // To be explicit, these are the non-parameter locals
- uint32_t locals_body_index = 0;
-
- switch (PM_NODE_TYPE(scope_node->ast_node)) {
- case PM_BLOCK_NODE: {
- locals_body_index = ((pm_block_node_t *)scope_node->ast_node)->locals_body_index;
- break;
- }
- case PM_DEF_NODE: {
- locals_body_index = ((pm_def_node_t *)scope_node->ast_node)->locals_body_index;
- break;
- }
- case PM_LAMBDA_NODE: {
- locals_body_index = ((pm_lambda_node_t *)scope_node->ast_node)->locals_body_index;
- break;
- }
- default: {
- }
- }
-
- if (scope_node->locals.size) {
- for (size_t i = locals_body_index; i < scope_node->locals.size; i++) {
- pm_constant_id_t constant_id = locals->ids[i];
- if (constant_id) {
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
- }
- }
- }
-
- // We fill in the block_locals, if they exist
- // lambda { |x; y| y }
- // ^
- if (block_locals && block_locals->size) {
- for (size_t i = 0; i < block_locals->size; i++, local_index++) {
- pm_constant_id_t constant_id = ((pm_block_local_variable_node_t *)block_locals->nodes[i])->name;
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- }
-
- //********END OF STEP 4**********
-
- // We set the index_lookup_table on the scope node so we can
- // refer to the parameters correctly
- scope_node->index_lookup_table = index_lookup_table;
- iseq_calc_param_size(iseq);
- iseq_set_local_table(iseq, local_table_for_iseq);
- scope_node->local_table_for_iseq_size = local_table_for_iseq->size;
-
- //********STEP 5************
- // Goal: compile anything that needed to be compiled
- if (keywords_list && keywords_list->size) {
- for (size_t i = 0; i < keywords_list->size; i++, local_index++) {
- pm_node_t *keyword_parameter_node = keywords_list->nodes[i];
- pm_constant_id_t name;
-
- switch (PM_NODE_TYPE(keyword_parameter_node)) {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^
- case PM_OPTIONAL_KEYWORD_PARAMETER_NODE: {
- pm_optional_keyword_parameter_node_t *cast = ((pm_optional_keyword_parameter_node_t *)keyword_parameter_node);
-
- pm_node_t *value = cast->value;
- name = cast->name;
-
- if (!(pm_static_literal_p(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)) {
- LABEL *end_label = NEW_LABEL(nd_line(&dummy_line_node));
-
- int index = pm_lookup_local_index(iseq, scope_node, name);
- int kw_bits_idx = table_size - body->param.keyword->bits_start;
- ADD_INSN2(ret, &dummy_line_node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(i));
- ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
- PM_COMPILE(value);
- ADD_SETLOCAL(ret, &dummy_line_node, index, 0);
-
- ADD_LABEL(ret, end_label);
- }
- break;
- }
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- case PM_REQUIRED_KEYWORD_PARAMETER_NODE: {
- break;
- }
- default: {
- rb_bug("Unexpected keyword parameter node type");
- }
- }
- }
- }
-
- if (optionals_list && 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++, local_index++) {
- 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.opt_table = (const VALUE *)opt_table;
- }
-
- if (requireds_list && requireds_list->size) {
- for (size_t i = 0; i < requireds_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *required = requireds_list->nodes[i];
- if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
- ADD_GETLOCAL(ret, &dummy_line_node, table_size - required_multis_hidden_index, 0);
- PM_COMPILE(required);
- }
- }
- }
-
- if (posts_list && posts_list->size) {
- for (size_t i = 0; i < posts_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *post = posts_list->nodes[i];
- if (PM_NODE_TYPE_P(post, PM_MULTI_TARGET_NODE)) {
- ADD_GETLOCAL(ret, &dummy_line_node, table_size - post_multis_hidden_index, 0);
- PM_COMPILE(post);
- }
- }
- }
-
- 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);
- if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
- PM_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;
- LABEL *target = NEW_LABEL(lineno);
- LABEL *old_start = ISEQ_COMPILE_DATA(iseq)->start_label;
-
- ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
- PM_COMPILE(for_node->index);
- PM_NOP;
- ADD_LABEL(ret, target);
- ISEQ_COMPILE_DATA(iseq)->start_label = target;
- pm_compile_node(iseq, (pm_node_t *)(scope_node->body), ret, src, popped, scope_node);
- ISEQ_COMPILE_DATA(iseq)->start_label = old_start;
- break;
- }
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
- pm_interpolated_regular_expression_node_t *cast = (pm_interpolated_regular_expression_node_t *) scope_node->ast_node;
-
- int parts_size = (int)cast->parts.size;
- if (parts_size > 0 && !PM_NODE_TYPE_P(cast->parts.nodes[0], PM_STRING_NODE)) {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_str_new(0, 0));
- parts_size++;
- }
-
- pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, src, false, scope_node, parser);
- ADD_INSN2(ret, &dummy_line_node, toregexp, INT2FIX(pm_reg_flags((pm_node_t *)cast)), INT2FIX(parts_size));
- break;
- }
- 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);
-
- if (scope_node->body) {
- PM_COMPILE_POPPED((pm_node_t *)scope_node->body);
- }
-
- ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
- ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0));
- return;
- }
- case ISEQ_TYPE_RESCUE: {
- iseq_set_exception_local_table(iseq);
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_RESCUE_MODIFIER_NODE)) {
- LABEL *lab = NEW_LABEL(lineno);
- LABEL *rescue_end = NEW_LABEL(lineno);
- ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_eStandardError);
- ADD_INSN1(ret, &dummy_line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
- ADD_INSN1(ret, &dummy_line_node, branchif, lab);
- ADD_INSN1(ret, &dummy_line_node, jump, rescue_end);
- ADD_LABEL(ret, lab);
- PM_COMPILE((pm_node_t *)scope_node->body);
- ADD_INSN(ret, &dummy_line_node, leave);
- ADD_LABEL(ret, rescue_end);
- ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
- }
- else {
- PM_COMPILE((pm_node_t *)scope_node->ast_node);
- }
- 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;
- }
- }
-
- st_free_table(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_NODE: {
- if (!popped) {
- pm_string_node_t *cast = (pm_string_node_t *) node;
- VALUE value = parse_string_encoded(node, &cast->unescaped, parser);
- if (node->flags & PM_STRING_FLAGS_FROZEN) {
- ADD_INSN1(ret, &dummy_line_node, putobject, rb_str_freeze(value));
- }
- else {
- ADD_INSN1(ret, &dummy_line_node, putstring, value);
- }
- }
- 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;
-
- PM_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 *cast = (pm_x_string_node_t *) node;
- VALUE value = parse_string_encoded(node, &cast->unescaped, parser);
-
- PM_PUTSELF;
- ADD_INSN1(ret, &dummy_line_node, putobject, value);
- 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;
-
- int flags = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
-
- int argc = 0;
-
- if (yield_node->arguments) {
- argc = pm_setup_args(yield_node->arguments, &flags, &keywords, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
- }
-
- ADD_INSN1(ret, &dummy_line_node, invokeblock, new_callinfo(iseq, 0, argc, flags, 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 ed0c7b4c91..0000000000
--- a/prism_compile.h
+++ /dev/null
@@ -1,29 +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;
- pm_node_t *parameters;
- pm_node_t *body;
- pm_constant_id_list_t locals;
- pm_parser_t *parser;
-
- // The size of the local table
- // on the iseq which includes
- // locals and hidden variables
- int local_table_for_iseq_size;
-
- ID *constants;
- st_table *index_lookup_table;
-
- // Some locals are defined at higher scopes than they are used. We can use
- // this offset to control which parent scopes local table we should be
- // referencing from the current scope.
- unsigned int local_depth_offset;
-} 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);
-bool *rb_ruby_prism_ptr(void);
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 a3fdb1783c..c31017128e 100644
--- a/proc.c
+++ b/proc.c
@@ -10,12 +10,11 @@
**********************************************************************/
#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"
@@ -24,6 +23,15 @@
#include "vm_core.h"
#include "yjit.h"
+#if !defined(__GNUC__) || __GNUC__ < 5 || defined(__MINGW32__)
+# define NO_CLOBBERED(v) (*(volatile VALUE *)&(v))
+#else
+# define NO_CLOBBERED(v) (v)
+#endif
+
+#define UPDATE_TYPED_REFERENCE(_type, _ref) *(_type*)&_ref = (_type)rb_gc_location((VALUE)_ref)
+#define UPDATE_REFERENCE(_ref) UPDATE_TYPED_REFERENCE(VALUE, _ref)
+
const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase);
struct METHOD {
@@ -48,39 +56,87 @@ 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)
+/* :FIXME: The way procs are cloned has been historically different from the
+ * way everything else are. @shyouhei is not sure for the intention though.
+ */
+#undef CLONESETUP
+static inline void
+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_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);
+ if (RB_FL_TEST(obj, RUBY_FL_EXIVAR)) rb_copy_generic_ivar(clone, 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 {
@@ -100,10 +156,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
};
@@ -126,15 +182,8 @@ static VALUE
proc_clone(VALUE self)
{
VALUE procval = rb_proc_dup(self);
- return rb_obj_clone_setup(self, procval, Qnil);
-}
-
-/* :nodoc: */
-static VALUE
-proc_dup(VALUE self)
-{
- VALUE procval = rb_proc_dup(self);
- return rb_obj_dup_setup(self, procval);
+ CLONESETUP(procval, self);
+ return procval;
}
/*
@@ -260,12 +309,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
@@ -277,10 +337,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
};
@@ -309,7 +369,7 @@ binding_dup(VALUE self)
rb_vm_block_copy(bindval, &dst->block, &src->block);
RB_OBJ_WRITE(bindval, &dst->pathobj, src->pathobj);
dst->first_lineno = src->first_lineno;
- return rb_obj_dup_setup(self, bindval);
+ return bindval;
}
/* :nodoc: */
@@ -317,7 +377,8 @@ static VALUE
binding_clone(VALUE self)
{
VALUE bindval = binding_dup(self);
- return rb_obj_clone_setup(self, bindval, Qnil);
+ CLONESETUP(bindval, self);
+ return bindval;
}
VALUE
@@ -331,44 +392,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:
- *
- * # 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
+ * calling +eval+ to execute the evaluated command in this
+ * environment. See also the description of class +Binding+.
*
- * # ...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
@@ -680,29 +713,6 @@ cfunc_proc_new(VALUE klass, VALUE ifunc)
return procval;
}
-VALUE
-rb_func_proc_dup(VALUE src_obj)
-{
- RUBY_ASSERT(rb_typeddata_is_instance_of(src_obj, &proc_data_type));
-
- rb_proc_t *src_proc;
- GetProcPtr(src_obj, src_proc);
- RUBY_ASSERT(vm_block_type(&src_proc->block) == block_type_ifunc);
-
- cfunc_proc_t *proc;
- VALUE proc_obj = TypedData_Make_Struct(rb_obj_class(src_obj), cfunc_proc_t, &proc_data_type, proc);
-
- memcpy(&proc->basic, src_proc, sizeof(rb_proc_t));
-
- VALUE *ep = *(VALUE **)&proc->basic.block.as.captured.ep = proc->env + VM_ENV_DATA_SIZE - 1;
- ep[VM_ENV_DATA_INDEX_FLAGS] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_FLAGS];
- ep[VM_ENV_DATA_INDEX_ME_CREF] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_ME_CREF];
- ep[VM_ENV_DATA_INDEX_SPECVAL] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_SPECVAL];
- ep[VM_ENV_DATA_INDEX_ENV] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_ENV];
-
- return proc_obj;
-}
-
static VALUE
sym_proc_new(VALUE klass, VALUE sym)
{
@@ -742,19 +752,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);
@@ -764,7 +773,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();
@@ -797,8 +806,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;
@@ -821,7 +838,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;
@@ -830,7 +847,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);
}
/*
@@ -843,44 +860,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");
}
/*
@@ -894,7 +908,7 @@ f_lambda_filter_non_literal(void)
static VALUE
f_lambda(VALUE _)
{
- f_lambda_filter_non_literal();
+ f_lambda_warn();
return rb_block_lambda();
}
@@ -1323,17 +1337,12 @@ proc_eq(VALUE self, VALUE other)
}
break;
case block_type_ifunc:
- if (self_block->as.captured.code.ifunc != \
+ if (self_block->as.captured.ep != \
+ other_block->as.captured.ep ||
+ self_block->as.captured.code.ifunc != \
other_block->as.captured.code.ifunc) {
return Qfalse;
}
-
- if (memcmp(
- ((cfunc_proc_t *)self_proc)->env,
- ((cfunc_proc_t *)other_proc)->env,
- sizeof(((cfunc_proc_t *)self_proc)->env))) {
- return Qfalse;
- }
break;
case block_type_proc:
if (self_block->as.proc != other_block->as.proc) {
@@ -1363,7 +1372,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);
@@ -1455,33 +1464,9 @@ rb_hash_proc(st_index_t hash, VALUE prc)
{
rb_proc_t *proc;
GetProcPtr(prc, proc);
-
- 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);
- hash = rb_st_hash_uint(hash, (st_index_t)proc->block.as.captured.code.ifunc->data);
- 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));
- }
-
- /* ifunc procs have their own allocated ep. If an ifunc is duplicated, they
- * will point to different ep but they should return the same hash code, so
- * we cannot include the ep in the hash. */
- if (vm_block_type(&proc->block) != block_type_ifunc) {
- hash = rb_hash_uint(hash, (st_index_t)proc->block.as.captured.ep);
- }
-
- return hash;
+ 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);
+ return rb_hash_uint(hash, (st_index_t)proc->block.as.captured.ep);
}
@@ -1499,7 +1484,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;
@@ -1610,25 +1595,42 @@ proc_to_proc(VALUE self)
}
static void
-bm_mark_and_move(void *ptr)
+bm_mark(void *ptr)
+{
+ struct METHOD *data = ptr;
+ 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;
- 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);
+ 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
+bm_memsize(const void *ptr)
+{
+ return sizeof(struct METHOD);
}
static const rb_data_type_t method_data_type = {
"method",
{
- bm_mark_and_move,
+ bm_mark,
RUBY_TYPED_DEFAULT_FREE,
- NULL, // No external memory to report,
- bm_mark_and_move,
+ bm_memsize,
+ bm_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
VALUE
@@ -1822,8 +1824,8 @@ method_eq(VALUE method, VALUE other)
return Qfalse;
Check_TypedStruct(method, &method_data_type);
- m1 = (struct METHOD *)RTYPEDDATA_GET_DATA(method);
- m2 = (struct METHOD *)RTYPEDDATA_GET_DATA(other);
+ m1 = (struct METHOD *)DATA_PTR(method);
+ m2 = (struct METHOD *)DATA_PTR(other);
klass1 = method_entry_defined_class(m1->me);
klass2 = method_entry_defined_class(m2->me);
@@ -1994,7 +1996,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:
@@ -2118,9 +2120,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) {
@@ -2239,7 +2242,7 @@ rb_mod_define_method_with_visibility(int argc, VALUE *argv, VALUE mod, const str
if (!id) id = rb_to_id(name);
if (is_method) {
- struct METHOD *method = (struct METHOD *)RTYPEDDATA_GET_DATA(body);
+ struct METHOD *method = (struct METHOD *)DATA_PTR(body);
if (method->me->owner != mod && !RB_TYPE_P(method->me->owner, T_MODULE) &&
!RTEST(rb_class_inherited_p(mod, method->me->owner))) {
if (FL_TEST(method->me->owner, FL_SINGLETON)) {
@@ -2379,7 +2382,17 @@ rb_obj_define_method(int argc, VALUE *argv, VALUE obj)
static VALUE
top_define_method(int argc, VALUE *argv, VALUE obj)
{
- return rb_mod_define_method(argc, argv, rb_top_main_class("define_method"));
+ 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);
}
/*
@@ -2407,25 +2420,7 @@ method_clone(VALUE self)
TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig);
clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data);
- rb_obj_clone_setup(self, clone, Qnil);
- RB_OBJ_WRITE(clone, &data->recv, orig->recv);
- RB_OBJ_WRITE(clone, &data->klass, orig->klass);
- RB_OBJ_WRITE(clone, &data->iclass, orig->iclass);
- RB_OBJ_WRITE(clone, &data->owner, orig->owner);
- RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
- return clone;
-}
-
-/* :nodoc: */
-static VALUE
-method_dup(VALUE self)
-{
- VALUE clone;
- struct METHOD *orig, *data;
-
- TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig);
- clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data);
- rb_obj_dup_setup(self, clone);
+ CLONESETUP(clone, self);
RB_OBJ_WRITE(clone, &data->recv, orig->recv);
RB_OBJ_WRITE(clone, &data->klass, orig->klass);
RB_OBJ_WRITE(clone, &data->iclass, orig->iclass);
@@ -3171,7 +3166,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));
@@ -3191,7 +3186,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);
@@ -3450,15 +3445,9 @@ env_clone(const rb_env_t *env, const rb_cref_t *cref)
}
new_body = ALLOC_N(VALUE, env->env_size);
+ MEMCPY(new_body, env->env, VALUE, env->env_size);
new_ep = &new_body[env->ep - env->env];
new_env = vm_env_new(new_ep, new_body, env->env_size, env->iseq);
-
- /* The memcpy has to happen after the vm_env_new because it can trigger a
- * GC compaction which can move the objects in the env. */
- MEMCPY(new_body, env->env, VALUE, env->env_size);
- /* VM_ENV_DATA_INDEX_ENV is set in vm_env_new but will get overwritten
- * by the memcpy above. */
- new_ep[VM_ENV_DATA_INDEX_ENV] = (VALUE)new_env;
RB_OBJ_WRITE(new_env, &new_ep[VM_ENV_DATA_INDEX_ME_CREF], (VALUE)cref);
VM_ASSERT(VM_ENV_ESCAPED_P(new_ep));
return new_env;
@@ -4299,7 +4288,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");
@@ -4335,7 +4324,6 @@ Init_Proc(void)
rb_define_method(rb_cMethod, "eql?", method_eq, 1);
rb_define_method(rb_cMethod, "hash", method_hash, 0);
rb_define_method(rb_cMethod, "clone", method_clone, 0);
- rb_define_method(rb_cMethod, "dup", method_dup, 0);
rb_define_method(rb_cMethod, "call", rb_method_call_pass_called_kw, -1);
rb_define_method(rb_cMethod, "===", rb_method_call_pass_called_kw, -1);
rb_define_method(rb_cMethod, "curry", rb_method_curry, -1);
@@ -4366,7 +4354,6 @@ Init_Proc(void)
rb_define_method(rb_cUnboundMethod, "eql?", unbound_method_eq, 1);
rb_define_method(rb_cUnboundMethod, "hash", method_hash, 0);
rb_define_method(rb_cUnboundMethod, "clone", method_clone, 0);
- rb_define_method(rb_cUnboundMethod, "dup", method_dup, 0);
rb_define_method(rb_cUnboundMethod, "arity", method_arity_m, 0);
rb_define_method(rb_cUnboundMethod, "inspect", method_inspect, 0);
rb_define_method(rb_cUnboundMethod, "to_s", method_inspect, 0);
diff --git a/process.c b/process.c
index aff350331b..dbe2be5b56 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,20 +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.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;
@@ -593,17 +604,17 @@ struct rb_process_status {
static const rb_data_type_t rb_process_status_type = {
.wrap_struct_name = "Process::Status",
.function = {
- .dmark = NULL,
.dfree = RUBY_DEFAULT_FREE,
- .dsize = NULL,
},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+ .data = NULL,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
rb_process_status_allocate(VALUE klass)
{
- struct rb_process_status *data;
+ struct rb_process_status *data = NULL;
+
return TypedData_Make_Struct(klass, struct rb_process_status, &rb_process_status_type, data);
}
@@ -615,25 +626,18 @@ rb_last_status_get(void)
/*
* call-seq:
- * 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:
+ * Process.last_status -> Process::Status or nil
*
- * Process.spawn('ruby', '-e', 'exit 13')
- * Process.wait
- * Process.last_status # => #<Process::Status: pid 14396 exit 13>
+ * Returns the status of the last executed child process in the
+ * current thread.
*
- * Process.spawn('ruby', '-e', 'exit 14')
- * Process.wait
- * Process.last_status # => #<Process::Status: pid 4692 exit 14>
+ * Process.wait Process.spawn("ruby", "-e", "exit 13")
+ * Process.last_status #=> #<Process::Status: pid 4825 exit 13>
*
- * 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)
@@ -645,7 +649,8 @@ VALUE
rb_process_status_new(rb_pid_t pid, int status, int error)
{
VALUE last_status = rb_process_status_allocate(rb_cProcessStatus);
- struct rb_process_status *data = RTYPEDDATA_GET_DATA(last_status);
+
+ struct rb_process_status *data = RTYPEDDATA_DATA(last_status);
data->pid = pid;
data->status = status;
data->error = error;
@@ -658,8 +663,7 @@ static VALUE
process_status_dump(VALUE status)
{
VALUE dump = rb_class_new_instance(0, 0, rb_cObject);
- struct rb_process_status *data;
- TypedData_Get_Struct(status, struct rb_process_status, &rb_process_status_type, data);
+ struct rb_process_status *data = RTYPEDDATA_DATA(status);
if (data->pid) {
rb_ivar_set(dump, id_status, INT2NUM(data->status));
rb_ivar_set(dump, id_pid, PIDT2NUM(data->pid));
@@ -684,42 +688,36 @@ 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
-pst_pid(VALUE status)
+pst_pid(VALUE pst)
{
- struct rb_process_status *data;
- TypedData_Get_Struct(status, struct rb_process_status, &rb_process_status_type, data);
+ struct rb_process_status *data = RTYPEDDATA_DATA(pst);
return data->pid;
}
static int
-pst_status(VALUE status)
+pst_status(VALUE pst)
{
- struct rb_process_status *data;
- TypedData_Get_Struct(status, struct rb_process_status, &rb_process_status_type, data);
+ struct rb_process_status *data = RTYPEDDATA_DATA(pst);
return data->status;
}
/*
* 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
@@ -733,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
@@ -795,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"
*
*/
@@ -823,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>"
*
*/
@@ -854,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
@@ -875,53 +867,20 @@ pst_equal(VALUE st1, VALUE st2)
/*
* call-seq:
- * stat & mask -> integer
- *
- * This method is deprecated as #to_i value is system-specific; use
- * predicate methods like #exited? or #stopped?, or getters like #exitstatus
- * or #stopsig.
+ * 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);
}
@@ -929,48 +888,20 @@ pst_bitand(VALUE st1, VALUE st2)
/*
* call-seq:
- * stat >> places -> integer
- *
- * This method is deprecated as #to_i value is system-specific; use
- * predicate methods like #exited? or #stopped?, or getters like #exitstatus
- * or #stopsig.
+ * 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);
}
@@ -978,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
@@ -996,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
@@ -1015,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
@@ -1032,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
@@ -1051,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
@@ -1069,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
@@ -1093,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
@@ -1116,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
@@ -1148,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;
@@ -1159,6 +1092,119 @@ 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(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;
+
+ 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->waiting_pids);
+ if (ccan_list_empty(&vm->waiting_pids)) {
+ waitpid_each(&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)
{
@@ -1169,6 +1215,90 @@ 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;
+}
+
+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->pid > 0 || ccan_list_empty(&vm->waiting_pids)) {
+ 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);
+ }
+}
+
static void *
waitpid_blocking_no_SIGCHLD(void *x)
{
@@ -1187,7 +1317,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)
@@ -1209,44 +1340,68 @@ rb_process_status_wait(rb_pid_t pid, int flags)
waitpid_state_init(&waitpid_state, pid, flags);
waitpid_state.ec = GET_EC();
- waitpid_no_SIGCHLD(&waitpid_state);
+ if (WAITPID_USE_SIGCHLD) {
+ waitpid_wait(&waitpid_state);
+ }
+ else {
+ waitpid_no_SIGCHLD(&waitpid_state);
+ }
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);
@@ -1271,7 +1426,7 @@ rb_waitpid(rb_pid_t pid, int *st, int flags)
VALUE status = rb_process_status_wait(pid, flags);
if (NIL_P(status)) return 0;
- struct rb_process_status *data = rb_check_typeddata(status, &rb_process_status_type);
+ struct rb_process_status *data = RTYPEDDATA_DATA(status);
pid = data->pid;
if (st) *st = data->status;
@@ -1331,155 +1486,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
@@ -1493,17 +1562,22 @@ proc_wait2(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * Process.waitall -> array
+ * Process.waitall -> [ [pid1,status1], ...]
+ *
+ * Waits for all children, returning an array of
+ * _pid_/_status_ pairs (where _status_ is a
+ * Process::Status object).
*
- * 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:
+ * fork { sleep 0.2; exit 2 } #=> 27432
+ * fork { sleep 0.1; exit 1 } #=> 27433
+ * fork { exit 0 } #=> 27434
+ * p Process.waitall
*
- * 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>]]
+ * <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
@@ -1561,41 +1635,48 @@ rb_detach_process(rb_pid_t pid)
/*
* call-seq:
- * Process.detach(pid) -> thread
+ * 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.
+ * 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 method is needed only when the parent process will never wait
- * for the child process.
+ * 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.
*
- * This example does not reap the second child process;
- * that process appears as a zombie in the process status (+ps+) output:
+ * The waiting thread has #pid method which returns the pid.
*
- * pid = Process.spawn('ruby', '-e', 'exit 13') # => 312691
- * sleep(1)
- * # Find zombies.
- * system("ps -ho pid,state -p #{pid}")
+ * In this first example, we don't reap the first child process, so
+ * it appears as a zombie in the process status display.
*
- * Output:
+ * p1 = fork { sleep 0.1 }
+ * p2 = fork { sleep 0.2 }
+ * Process.waitpid(p2)
+ * sleep 2
+ * system("ps -ho pid,state -p #{p1}")
*
- * 312716 Z
+ * <em>produces:</em>
*
- * This example also does not reap the second child process,
- * but it does detach the process so that it does not become a zombie:
+ * 27389 Z
*
- * 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.
+ * In the next example, Process::detach is used to reap
+ * the child automatically.
*
- * The waiting thread can return the pid of the detached child process:
- *
- * 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
@@ -1665,13 +1746,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)
@@ -1680,33 +1774,15 @@ before_fork_ruby(void)
}
static void
-after_fork_ruby(rb_pid_t pid)
+after_fork_ruby(void)
{
- if (pid == 0) {
- // child
- clear_pid_cache();
- rb_thread_atfork();
- }
- else {
- // parent
- after_exec();
- }
+ rb_threadptr_pending_interrupt_clear(GET_THREAD());
+ 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
@@ -1838,7 +1914,7 @@ memsize_exec_arg(const void *ptr)
static const rb_data_type_t exec_arg_data_type = {
"exec_arg",
{mark_exec_arg, RUBY_TYPED_DEFAULT_FREE, memsize_exec_arg},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
#ifdef _WIN32
@@ -2782,7 +2858,6 @@ rb_execarg_setenv(VALUE execarg_obj, VALUE env)
struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
env = !NIL_P(env) ? rb_check_exec_env(env, &eargp->path_env) : Qfalse;
eargp->env_modification = env;
- RB_GC_GUARD(execarg_obj);
}
static int
@@ -2980,7 +3055,6 @@ execarg_parent_end(VALUE execarg_obj)
}
errno = err;
- RB_GC_GUARD(execarg_obj);
return execarg_obj;
}
@@ -3022,6 +3096,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);
@@ -3046,89 +3121,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).
+ * exec([env,] command... [,options])
*
- * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ * Replaces the current process by running the given external _command_, which
+ * can take one of the following forms:
*
- * Argument +options+ is a hash of options for the new process;
- * see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ * [<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)
*
- * The first required argument is one of the following:
+ * In the first form, the string is taken as a command line that is subject to
+ * shell expansion before being executed.
*
- * - +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.
+ * 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+.
*
- * <b>Argument +command_line+</b>
+ * If the string from the first form (<code>exec("command")</code>) follows
+ * these simple rules:
*
- * \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:
+ * * no meta characters,
+ * * not starting with shell reserved word or special built-in,
*
- * exec('if true; then echo "Foo"; fi') # Shell reserved word.
- * exec('echo') # Built-in.
- * exec('date > date.tmp') # Contains meta character.
+ * Ruby invokes the command directly without shell.
*
- * The command line may also contain arguments and options for the command:
+ * You can force shell invocation by adding ";" to the string (because ";" is
+ * a meta character).
*
- * exec('echo "Foo"')
+ * 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.
*
- * Output:
+ * 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.
*
- * Foo
+ * 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.
*
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
+ * 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).
*
- * Raises an exception if the new process could not execute.
+ * This behavior is modified by the given +env+ and +options+ parameters. See
+ * ::spawn for details.
*
- * <b>Argument +exe_path+</b>
+ * If the command fails to execute (typically Errno::ENOENT when
+ * it was not found) a SystemCallError exception is raised.
*
- * Argument +exe_path+ is one of the following:
+ * 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+.
*
- * - 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.
+ * The modified attributes may be retained when <code>exec(2)</code> system
+ * call fails.
*
- * Example:
+ * For example, hard resource limits are not restorable.
*
- * exec('/usr/bin/date')
+ * Consider to create a child process using ::spawn or Kernel#system if this
+ * is not acceptable.
*
- * Output:
+ * exec "echo *" # echoes list of files in current directory
+ * # never get here
*
- * Sat Aug 26 09:38:00 AM CDT 2023
- *
- * Ruby invokes the executable directly, with no shell and no shell expansion:
- *
- * exec('doesnt_exist') # Raises Errno::ENOENT
- *
- * If one or more +args+ is given, each is an argument or option
- * to be passed to the executable:
- *
- * exec('echo', 'C*')
- * exec('echo', 'hello', 'world')
- *
- * Output:
- *
- * C*
- * hello world
- *
- * Raises an exception if the new process could not execute.
+ * exec "echo", "*" # echoes an asterisk
+ * # never get here
*/
static VALUE
@@ -3353,13 +3416,6 @@ run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, s
ERRMSG("dup");
goto fail;
}
- // without this, kqueue timer_th.event_fd fails with a reserved FD did not have close-on-exec
- // in #assert_close_on_exec because the FD_CLOEXEC is not dup'd by default
- if (fd_get_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen)) {
- if (fd_set_cloexec(extra_fd, errmsg, errmsg_buflen)) {
- goto fail;
- }
- }
rb_update_max_fd(extra_fd);
}
else {
@@ -4098,10 +4154,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();
@@ -4126,6 +4188,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;
@@ -4135,6 +4205,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,
@@ -4170,12 +4264,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);
}
@@ -4190,7 +4285,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
@@ -4220,21 +4315,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;
}
@@ -4313,62 +4409,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
@@ -4420,18 +4481,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
@@ -4482,47 +4538,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
@@ -4561,16 +4613,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
@@ -4654,7 +4703,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;
}
@@ -4676,28 +4725,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(rb_execarg_get(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
@@ -4723,131 +4774,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.
@@ -4855,10 +4843,11 @@ 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);
+ struct rb_process_status *data = RTYPEDDATA_DATA(status);
+
// Set the last status:
rb_obj_freeze(status);
- th->last_status = status;
+ GET_THREAD()->last_status = status;
if (data->status == EXIT_SUCCESS) {
return Qtrue;
@@ -4901,111 +4890,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].
+ * 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
*
- * Returns the process ID (pid) of the new process,
- * without waiting for it to complete.
+ * For stdout and stderr (and combination of them),
+ * it is opened in write mode.
+ * Otherwise read mode is used.
*
- * To avoid zombie processes, the parent process should call either:
+ * For specifying flags and permission of file creation explicitly,
+ * an array is used instead.
*
- * - Process.wait, to collect the termination statuses of its children.
- * - Process.detach, to register disinterest in their status.
+ * 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])
*
- * 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).
+ * 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.
*
- * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ * If an array of IOs and integers are specified as a hash key,
+ * all the elements are redirected.
*
- * Argument +options+ is a hash of options for the new process;
- * see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ * # stdout and stderr is redirected to log file.
+ * # The file "log" is opened just once.
+ * pid = spawn(command, [:out, :err]=>["log", "w"])
*
- * The first required argument is one of the following:
+ * 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.
*
- * - +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.
+ * # stdout and stderr is redirected to log file.
+ * # The file "log" is opened just once.
+ * pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
*
- * <b>Argument +command_line+</b>
+ * \[: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.
*
- * \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:
+ * io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
+ * p io.read #=> "out\nerr\n"
*
- * 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 <code>:chdir</code> key in +options+ specifies the current directory.
*
- * The command line may also contain arguments and options for the command:
+ * pid = spawn(command, :chdir=>"/var/tmp")
*
- * spawn('echo "Foo"') # => 799031
- * Process.wait # => 799031
+ * 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.
*
- * Output:
+ * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
+ * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
*
- * Foo
+ * :close_others is false by default for spawn and IO.popen.
*
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
+ * Note that fds which close-on-exec flag is already set are closed
+ * regardless of :close_others option.
*
- * Raises an exception if the new process could not execute.
+ * So IO.pipe and spawn can be used as IO.popen.
*
- * <b>Argument +exe_path+</b>
+ * # 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
*
- * Argument +exe_path+ is one of the following:
+ * :close is specified as a hash value to close a fd individually.
*
- * - The string path to an executable to be called:
+ * f = open(foo)
+ * system(command, f=>:close) # don't inherit f.
*
- * spawn('/usr/bin/date') # Path to date on Unix-style system.
- * Process.wait
+ * If a file descriptor need to be inherited,
+ * io=>io can be used.
*
- * Output:
+ * # 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
*
- * Thu Aug 31 10:06:48 AM CDT 2023
+ * It is also possible to exchange file descriptors.
*
- * - A 2-element array containing the path to an executable
- * and the string to be used as the name of the executing process:
+ * pid = spawn(command, :out=>:err, :err=>:out)
*
- * pid = spawn(['sleep', 'Hello!'], '1') # 2-element array.
- * p `ps -p #{pid} -o command=`
+ * 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.
*
- * Output:
- *
- * "Hello! 1\n"
- *
- * Ruby invokes the executable directly, with no shell and no shell expansion.
- *
- * If one or more +args+ is given, each is an argument or option
- * to be passed to the executable:
- *
- * spawn('echo', 'C*') # => 799392
- * Process.wait # => 799392
- * spawn('echo', 'hello', 'world') # => 799393
- * Process.wait # => 799393
- *
- * Output:
- *
- * C*
- * hello world
- *
- * Raises an exception if the new process could not execute.
+ * See Kernel.exec for the standard shell.
*/
static VALUE
@@ -5037,18 +5186,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
@@ -5061,7 +5211,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 {
@@ -5079,13 +5229,13 @@ rb_f_sleep(int argc, VALUE *argv, VALUE _)
#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
/*
* call-seq:
- * Process.getpgrp -> integer
+ * Process.getpgrp -> integer
*
- * Returns the process group ID for the current process:
- *
- * 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
@@ -5111,11 +5261,10 @@ proc_getpgrp(VALUE _)
#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
/*
* call-seq:
- * Process.setpgrp -> 0
- *
- * Equivalent to <tt>setpgid(0, 0)</tt>.
+ * Process.setpgrp -> 0
*
- * Not available on all platforms.
+ * Equivalent to <code>setpgid(0,0)</code>. Not available on all
+ * platforms.
*/
static VALUE
@@ -5140,13 +5289,12 @@ proc_setpgrp(VALUE _)
#if defined(HAVE_GETPGID)
/*
* call-seq:
- * Process.getpgid(pid) -> integer
- *
- * Returns the process group ID for the given process ID +pid+:
+ * Process.getpgid(pid) -> integer
*
- * 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
@@ -5166,12 +5314,10 @@ proc_getpgid(VALUE obj, VALUE pid)
#ifdef HAVE_SETPGID
/*
* call-seq:
- * Process.setpgid(pid, pgid) -> 0
- *
- * Sets the process group ID for the process given by process ID +pid+
- * to +pgid+.
+ * Process.setpgid(pid, integer) -> 0
*
- * 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
@@ -5193,16 +5339,15 @@ proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
#ifdef HAVE_GETSID
/*
* call-seq:
- * Process.getsid(pid = nil) -> integer
- *
- * Returns the session ID of the given process ID +pid+,
- * or of the current process if not given:
+ * Process.getsid() -> integer
+ * Process.getsid(pid) -> integer
*
- * Process.getsid # => 27422
- * Process.getsid(0) # => 27422
- * Process.getsid(Process.pid()) # => 27422
+ * Returns the session ID for the given process id. If not given,
+ * return current process sid. Not available on all platforms.
*
- * 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 _)
@@ -5229,15 +5374,13 @@ static rb_pid_t ruby_setsid(void);
#endif
/*
* call-seq:
- * 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 -> integer
*
- * 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
@@ -5285,26 +5428,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
@@ -5328,18 +5464,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
@@ -5587,24 +5719,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
@@ -5624,54 +5754,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
@@ -6250,14 +6380,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
+ * Process.uid -> integer
+ * Process::UID.rid -> integer
+ * Process::Sys.getuid -> integer
*
- * Returns the (real) user ID of the current process.
- *
- * Process.uid # => 1000
+ * Returns the (real) user ID of this process.
*
+ * Process.uid #=> 501
*/
static VALUE
@@ -6271,13 +6400,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
- *
- * Sets the (user) user ID for the current process to +new_uid+:
+ * Process.uid= user -> numeric
*
- * Process.uid = 1000 # => 1000
- *
- * Not available on all platforms.
+ * Sets the (user) user ID for this process. Not available on all
+ * platforms.
*/
static VALUE
@@ -6652,14 +6778,13 @@ p_sys_issetugid(VALUE obj)
/*
* call-seq:
- * Process.gid -> integer
- * Process::GID.rid -> integer
- * Process::Sys.getgid -> integer
+ * Process.gid -> integer
+ * Process::GID.rid -> integer
+ * Process::Sys.getgid -> integer
*
- * Returns the (real) group ID for the current process:
- *
- * Process.gid # => 1000
+ * Returns the (real) group ID for this process.
*
+ * Process.gid #=> 500
*/
static VALUE
@@ -6673,12 +6798,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
@@ -6762,23 +6884,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
*
*/
@@ -6815,14 +6940,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]
*
*/
@@ -6864,21 +6989,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:
+ * Process.initgroups(username, gid) -> array
*
- * - The group IDs of those groups to which the user given by +username+ belongs.
- * - The group ID +gid+.
+ * 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.
*
- * Example:
+ * 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]
*
- * 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]
- *
- * Not available on all platforms.
*/
static VALUE
@@ -6896,13 +7019,12 @@ proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
/*
* call-seq:
- * Process.maxgroups -> integer
+ * Process.maxgroups -> integer
*
- * Returns the maximum number of group IDs allowed
- * in the supplemental group access list:
- *
- * Process.maxgroups # => 32
+ * Returns the maximum number of GIDs allowed in the supplemental
+ * group access list.
*
+ * Process.maxgroups #=> 32
*/
static VALUE
@@ -6917,10 +7039,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
@@ -6951,22 +7073,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
@@ -6985,16 +7101,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;
@@ -7010,7 +7126,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);
@@ -7223,14 +7339,13 @@ p_gid_change_privilege(VALUE obj, VALUE id)
/*
* call-seq:
- * Process.euid -> integer
- * Process::UID.eid -> integer
- * Process::Sys.geteuid -> integer
- *
- * Returns the effective user ID for the current process.
+ * Process.euid -> integer
+ * Process::UID.eid -> integer
+ * Process::Sys.geteuid -> integer
*
- * Process.euid # => 501
+ * Returns the effective user ID for this process.
*
+ * Process.euid #=> 501
*/
static VALUE
@@ -7266,11 +7381,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
+ * Process.euid= user
*
- * Sets the effective user ID for the current process.
- *
- * Not available on all platforms.
+ * Sets the effective user ID for this process. Not available on all
+ * platforms.
*/
static VALUE
@@ -7348,15 +7462,14 @@ p_uid_grant_privilege(VALUE obj, VALUE id)
/*
* call-seq:
- * Process.egid -> integer
- * Process::GID.eid -> integer
- * Process::Sys.geteid -> integer
+ * Process.egid -> integer
+ * Process::GID.eid -> integer
+ * Process::Sys.geteid -> integer
*
- * Returns the effective group ID for the current process:
+ * Returns the effective group ID for this process. Not available on
+ * all platforms.
*
- * Process.egid # => 500
- *
- * Not available on all platforms.
+ * Process.egid #=> 500
*/
static VALUE
@@ -7370,11 +7483,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
+ * Process.egid = integer -> integer
*
- * Sets the effective group ID for the current process.
- *
- * Not available on all platforms.
+ * Sets the effective group ID for this process. Not available on all
+ * platforms.
*/
static VALUE
@@ -7847,15 +7959,14 @@ get_clk_tck(void)
/*
* call-seq:
- * Process.times -> process_tms
+ * Process.times -> aProcessTms
*
- * Returns a Process::Tms structure that contains user and system CPU times
- * for the current process, and for its children processes:
+ * Returns a <code>Tms</code> structure (see Process::Tms)
+ * that contains user and system CPU times for this process,
+ * and also for children processes.
*
- * Process.times
- * # => #<struct Process::Tms utime=55.122118, stime=35.533068, cutime=0.0, cstime=0.002846>
- *
- * 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
@@ -8110,174 +8221,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 _)
@@ -8292,9 +8361,7 @@ rb_clock_gettime(int argc, VALUE *argv, VALUE _)
VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
VALUE clk_id = argv[0];
-#ifdef HAVE_CLOCK_GETTIME
clockid_t c;
-#endif
if (SYMBOL_P(clk_id)) {
#ifdef CLOCK_REALTIME
@@ -8454,17 +8521,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);
@@ -8472,39 +8537,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 a clock resolution as determined by POSIX function
- * {clock_getres()}[https://man7.org/linux/man-pages/man3/clock_getres.3.html]:
+ * Returns an estimate of the resolution of a +clock_id+ using the POSIX
+ * <code>clock_getres()</code> function.
*
- * Process.clock_getres(:CLOCK_REALTIME) # => 1.0e-09
+ * 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.
*
- * See Process.clock_gettime for the values of +clock_id+ and +unit+.
+ * +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+.
*
- * Examples:
+ * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
*
- * 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
+ * +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+.
*
- * 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+):
+ * +Process.clock_getres+ also accepts +:hertz+ as +unit+.
+ * +:hertz+ means the reciprocal of +:float_second+.
*
- * 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
+ * +: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.
+ *
+ * <code>Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
+ * returns the clock ticks per second.
+ *
+ * <code>Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
+ * returns CLOCKS_PER_SEC.
+ *
+ * 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 _)
@@ -8516,9 +8587,7 @@ rb_clock_getres(int argc, VALUE *argv, VALUE _)
timetick_int_t denominators[2];
int num_numerators = 0;
int num_denominators = 0;
-#ifdef HAVE_CLOCK_GETRES
clockid_t c;
-#endif
VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
VALUE clk_id = argv[0];
@@ -8625,17 +8694,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)) {
@@ -8660,82 +8727,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
@@ -8749,363 +8772,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
@@ -9206,8 +8876,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 5bf84c7c83..e608e4e232 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,896 +921,430 @@ 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);
- }
+ basket->type = basket_type_move;
- *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->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;
-}
+ if (r) {
+ bool retry_shift = 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;
-
- 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);
-}
-
-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)
-{
- 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
-
+// select(r1, r2, r3, receive: true, yield: obj)
static VALUE
-ractor_selector_create(VALUE klass)
+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;
- VALUE selv = TypedData_Make_Struct(klass, 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(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(GET_RACTOR(), 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(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)
-{
- VALUE selv = (VALUE)data;
- rb_ractor_t *r = (rb_ractor_t *)key;
- ractor_selector_remove(selv, r->pub.self);
- return ST_CONTINUE;
-}
-
-static VALUE
-ractor_selector_clear(VALUE selv)
-{
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
-
- st_foreach(s->take_ractors, ractor_selector_clear_i, (st_data_t)selv);
- st_clear(s->take_ractors);
- return selv;
-}
-
-static VALUE
-ractor_selector_empty_p(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(VALUE selv, VALUE do_receivev, VALUE do_yieldv, VALUE yield_value, VALUE move)
-{
- rb_execution_context_t *ec = GET_EC();
- 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(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(selv, taken_basket.sender);
- break;
- default:
- break;
- }
+ cleanup:
+ RUBY_DEBUG_LOG("cleanup actions (%s)", wait_status_str(wait_status));
- RUBY_DEBUG_LOG("taken_basket:%s", basket_type_name(taken_basket.type.e));
-
- ret_v = ractor_basket_accept(&taken_basket);
- ret_r = taken_basket.sender;
- success:
- return rb_ary_new_from_args(2, ret_r, ret_v);
-}
+ if (cr->sync.wait.yielded_basket.type != basket_type_none) {
+ ractor_basket_clear(&cr->sync.wait.yielded_basket);
+ }
-static VALUE
-ractor_selector_wait(int argc, VALUE *argv, VALUE selector)
-{
- VALUE options;
- ID keywords[3];
- VALUE values[3];
+ 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);
- keywords[0] = rb_intern("receive");
- keywords[1] = rb_intern("yield_value");
- keywords[2] = rb_intern("move");
+ if (interrupted) {
+ rb_vm_check_ints_blocking(ec);
+ interrupted = false;
+ goto restart;
+ }
- rb_scan_args(argc, argv, "0:", &options);
- rb_get_kwargs(options, keywords, 0, numberof(values), values);
- return ractor_selector__wait(selector,
- values[0] == Qundef ? Qfalse : RTEST(values[0]),
- values[1] != Qundef, values[1], values[2]);
+ VM_ASSERT(!UNDEF_P(ret));
+ return ret;
}
static VALUE
-ractor_selector_new(int argc, VALUE *ractors, VALUE klass)
+ractor_yield(rb_execution_context_t *ec, rb_ractor_t *r, VALUE obj, VALUE move)
{
- VALUE selector = ractor_selector_create(klass);
-
- for (int i=0; i<argc; i++) {
- ractor_selector_add(selector, ractors[i]);
- }
-
- return selector;
+ VALUE ret_r;
+ ractor_select(ec, NULL, 0, obj, RTEST(move) ? true : false, &ret_r);
+ return Qnil;
}
static VALUE
-ractor_select_internal(rb_execution_context_t *ec, VALUE self, VALUE ractors, VALUE do_receive, VALUE do_yield, VALUE yield_value, VALUE move)
+ractor_take(rb_execution_context_t *ec, rb_ractor_t *r)
{
- VALUE selector = ractor_selector_new(RARRAY_LENINT(ractors), (VALUE *)RARRAY_CONST_PTR(ractors), rb_cRactorSelector);
- VALUE result;
- int state;
-
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG() == TAG_NONE)) {
- result = ractor_selector__wait(selector, do_receive, do_yield, yield_value, move);
- }
- else {
- // ensure
- ractor_selector_clear(selector);
-
- // jump
- EC_JUMP_TAG(ec, state);
- }
- EC_POP_TAG();
-
- RB_GC_GUARD(ractors);
- return result;
+ VALUE ret_r;
+ VALUE v = ractor_select(ec, &r->pub.self, 1, Qundef, false, &ret_r);
+ return v;
}
-// Ractor#close_incoming
-
static VALUE
ractor_close_incoming(rb_execution_context_t *ec, rb_ractor_t *r)
{
@@ -1833,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");
}
}
@@ -1845,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)
{
@@ -1854,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;
@@ -1934,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();
@@ -2045,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)
@@ -2058,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
@@ -2113,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);
@@ -2129,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.
}
}
@@ -2156,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);
@@ -2186,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++) {
@@ -2202,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());
@@ -2224,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;
}
@@ -2324,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)
{
@@ -2333,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);
}
@@ -2430,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
@@ -2467,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);
@@ -2481,23 +1977,7 @@ rb_ractor_terminate_all(void)
rb_execution_context_t *
rb_vm_main_ractor_ec(rb_vm_t *vm)
{
- /* This code needs to carefully work around two bugs:
- * - Bug #20016: When M:N threading is enabled, running_ec is NULL if no thread is
- * actually currently running (as opposed to without M:N threading, when
- * running_ec will still point to the _last_ thread which ran)
- * - Bug #20197: If the main thread is sleeping, setting its postponed job
- * interrupt flag is pointless; it won't look at the flag until it stops sleeping
- * for some reason. It would be better to set the flag on the running ec, which
- * will presumably look at it soon.
- *
- * Solution: use running_ec if it's set, otherwise fall back to the main thread ec.
- * This is still susceptible to some rare race conditions (what if the last thread
- * to run just entered a long-running sleep?), but seems like the best balance of
- * robustness and complexity.
- */
- rb_execution_context_t *running_ec = vm->ractor.main_ractor->threads.running_ec;
- if (running_ec) { return running_ec; }
- return vm->ractor.main_thread->ec;
+ return vm->ractor.main_ractor->threads.running_ec;
}
static VALUE
@@ -2506,29 +1986,6 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
rb_raise(rb_eRactorMovedError, "can not send any methods to a moved object");
}
-#ifndef USE_RACTOR_SELECTOR
-#define USE_RACTOR_SELECTOR 0
-#endif
-
-RUBY_SYMBOL_EXPORT_BEGIN
-void rb_init_ractor_selector(void);
-RUBY_SYMBOL_EXPORT_END
-
-void
-rb_init_ractor_selector(void)
-{
- rb_cRactorSelector = rb_define_class_under(rb_cRactor, "Selector", rb_cObject);
- rb_undef_alloc_func(rb_cRactorSelector);
-
- rb_define_singleton_method(rb_cRactorSelector, "new", ractor_selector_new , -1);
- rb_define_method(rb_cRactorSelector, "add", ractor_selector_add, 1);
- rb_define_method(rb_cRactorSelector, "remove", ractor_selector_remove, 1);
- rb_define_method(rb_cRactorSelector, "clear", ractor_selector_clear, 0);
- rb_define_method(rb_cRactorSelector, "empty?", ractor_selector_empty_p, 0);
- rb_define_method(rb_cRactorSelector, "wait", ractor_selector_wait, -1);
- rb_define_method(rb_cRactorSelector, "_wait", ractor_selector__wait, 4);
-}
-
/*
* Document-class: Ractor::ClosedError
*
@@ -2648,10 +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);
-
-#if USE_RACTOR_SELECTOR
- rb_init_ractor_selector();
-#endif
}
void
@@ -2797,6 +2250,19 @@ obj_hash_traverse_i(VALUE key, VALUE val, VALUE ptr)
return ST_CONTINUE;
}
+static enum rb_id_table_iterator_result
+obj_hash_iv_traverse_i(VALUE val, void *ptr)
+{
+ struct obj_traverse_callback_data *d = (struct obj_traverse_callback_data *)ptr;
+
+ if (obj_traverse_i(val, d->data)) {
+ d->stop = true;
+ return ID_TABLE_STOP;
+ }
+
+ return ID_TABLE_CONTINUE;
+}
+
static void
obj_traverse_reachable_i(VALUE obj, void *ptr)
{
@@ -2812,25 +2278,12 @@ 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;
}
static int
-obj_traverse_ivar_foreach_i(ID key, VALUE val, st_data_t ptr)
-{
- struct obj_traverse_callback_data *d = (struct obj_traverse_callback_data *)ptr;
-
- if (obj_traverse_i(val, d->data)) {
- d->stop = true;
- return ST_STOP;
- }
-
- return ST_CONTINUE;
-}
-
-static int
obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
{
if (RB_SPECIAL_CONST_P(obj)) return 0;
@@ -2846,12 +2299,14 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
return 0;
}
- struct obj_traverse_callback_data d = {
- .stop = false,
- .data = data,
- };
- rb_ivar_foreach(obj, obj_traverse_ivar_foreach_i, (st_data_t)&d);
- if (d.stop) return 1;
+ 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->numiv; i++) {
+ VALUE val = ivtbl->ivptr[i];
+ if (!UNDEF_P(val) && obj_traverse_i(val, data)) return 1;
+ }
+ }
switch (BUILTIN_TYPE(obj)) {
// no child node
@@ -2865,7 +2320,25 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
break;
case T_OBJECT:
- /* Instance variables already traversed. */
+ {
+ if (rb_shape_obj_too_complex(obj)) {
+ struct obj_traverse_callback_data d = {
+ .stop = false,
+ .data = data,
+ };
+ rb_id_table_foreach_values(ROBJECT_IV_HASH(obj), obj_hash_iv_traverse_i, &d);
+ if (d.stop) return 1;
+ }
+ else {
+ uint32_t len = ROBJECT_IV_COUNT(obj);
+ VALUE *ptr = ROBJECT_IVPTR(obj);
+
+ for (uint32_t i=0; i<len; i++) {
+ VALUE val = ptr[i];
+ if (!UNDEF_P(val) && obj_traverse_i(val, data)) return 1;
+ }
+ }
+ }
break;
case T_ARRAY:
@@ -3058,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
@@ -3101,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,
@@ -3205,28 +2681,28 @@ obj_hash_traverse_replace_i(st_data_t *key, st_data_t *val, st_data_t ptr, int e
return ST_CONTINUE;
}
-static int
-obj_iv_hash_traverse_replace_foreach_i(st_data_t _key, st_data_t _val, st_data_t _data, int _x)
+static enum rb_id_table_iterator_result
+obj_iv_hash_traverse_replace_foreach_i(VALUE val, void *data)
{
- return ST_REPLACE;
+ return ID_TABLE_REPLACE;
}
-static int
-obj_iv_hash_traverse_replace_i(st_data_t * _key, st_data_t * val, st_data_t ptr, int exists)
+static enum rb_id_table_iterator_result
+obj_iv_hash_traverse_replace_i(VALUE *val, void *ptr, int exists)
{
struct obj_traverse_replace_callback_data *d = (struct obj_traverse_replace_callback_data *)ptr;
struct obj_traverse_replace_data *data = d->data;
- if (obj_traverse_replace_i(*(VALUE *)val, data)) {
+ if (obj_traverse_replace_i(*val, data)) {
d->stop = true;
- return ST_STOP;
+ return ID_TABLE_STOP;
}
- else if (*(VALUE *)val != data->replacement) {
- VALUE v = *(VALUE *)val = data->replacement;
+ else if (*val != data->replacement) {
+ VALUE v = *val = data->replacement;
RB_OBJ_WRITTEN(d->src, Qundef, v);
}
- return ST_CONTINUE;
+ return ID_TABLE_CONTINUE;
}
static struct st_table *
@@ -3234,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++;
}
}
@@ -3300,26 +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);
-
- if (UNLIKELY(rb_shape_obj_too_complex(obj))) {
- struct obj_traverse_replace_callback_data d = {
- .stop = false,
- .data = data,
- .src = obj,
- };
- rb_st_foreach_with_replace(
- ivtbl->as.complex.table,
- obj_iv_hash_traverse_replace_foreach_i,
- obj_iv_hash_traverse_replace_i,
- (st_data_t)&d
- );
- if (d.stop) return 1;
- }
- else {
- 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]);
}
}
}
@@ -3340,25 +2806,29 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_OBJECT:
{
if (rb_shape_obj_too_complex(obj)) {
+ struct rb_id_table * table = ROBJECT_IV_HASH(obj);
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
.src = obj,
};
- rb_st_foreach_with_replace(
- ROBJECT_IV_HASH(obj),
- obj_iv_hash_traverse_replace_foreach_i,
- obj_iv_hash_traverse_replace_i,
- (st_data_t)&d
- );
- if (d.stop) return 1;
+ rb_id_table_foreach_values_with_replace(table,
+ obj_iv_hash_traverse_replace_foreach_i,
+ obj_iv_hash_traverse_replace_i,
+ (void *)&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);
- for (uint32_t i = 0; i < len; i++) {
- CHECK_AND_REPLACE(ptr[i]);
+ for (uint32_t i=0; i<len; i++) {
+ if (!UNDEF_P(ptr[i])) {
+ CHECK_AND_REPLACE(ptr[i]);
+ }
}
}
}
@@ -3367,6 +2837,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);
@@ -3381,8 +2854,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,
@@ -3407,6 +2884,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);
@@ -3507,8 +2987,6 @@ ractor_moved_bang(VALUE obj)
rv->v3 = 0;
rv->flags = rv->flags & ~fl_users;
- if (BUILTIN_TYPE(obj) == T_OBJECT) ROBJECT_SET_SHAPE_ID(obj, ROOT_SHAPE_ID);
-
// TODO: record moved location
}
diff --git a/ractor.rb b/ractor.rb
index d18062ca07..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,25 +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?
- if ractors.delete Ractor.current
- do_receive = true
- else
- do_receive = false
- end
-
- __builtin_ractor_select_internal ractors, do_receive, !yield_unspecified, yield_value, move
+ __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
@@ -382,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
@@ -390,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.
#
@@ -418,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
@@ -451,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"
@@ -471,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.
@@ -500,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}
@@ -510,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
@@ -519,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
@@ -536,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
@@ -554,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'
@@ -571,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'
@@ -589,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
@@ -607,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
@@ -639,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)
@@ -650,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'
@@ -661,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.
#
@@ -676,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"}
@@ -689,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}"}
@@ -738,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
@@ -756,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
@@ -777,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));
@@ -796,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 e607cf5f2f..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
-
-# if defined(__arm64__) || defined(__aarch64__)
+ #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/random.c b/random.c
index 5cd2d917a4..4b5b7ab6c4 100644
--- a/random.c
+++ b/random.c
@@ -157,12 +157,6 @@ rand_start(rb_random_mt_t *r)
static rb_ractor_local_key_t default_rand_key;
-void
-rb_free_default_rand_key(void)
-{
- xfree(default_rand_key);
-}
-
static void
default_rand_mark(void *ptr)
{
diff --git a/range.c b/range.c
index f66d23d07b..6d90ecf4f3 100644
--- a/range.c
+++ b/range.c
@@ -532,11 +532,7 @@ range_step(int argc, VALUE *argv, VALUE range)
rb_raise(rb_eTypeError, "can't iterate from %s",
rb_obj_classname(b));
}
- if (!NIL_P(e))
- range_each_func(range, step_i, (VALUE)iter);
- else
- for (;; b = rb_funcallv(b, id_succ, 0, 0))
- step_i(b, (VALUE)iter);
+ range_each_func(range, step_i, (VALUE)iter);
}
}
return range;
@@ -607,10 +603,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 +645,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 +692,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 +751,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 +763,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 +835,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,144 +996,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 (NIL_P(end)) {
- rb_raise(rb_eTypeError, "can't iterate from %s",
- rb_obj_classname(end));
- }
-
- 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
@@ -1844,6 +1678,7 @@ range_inspect(VALUE range)
}
static VALUE range_include_internal(VALUE range, VALUE val);
+static VALUE range_string_cover_internal(VALUE range, VALUE val);
VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
/*
@@ -1888,6 +1723,8 @@ VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
static VALUE
range_eqq(VALUE range, VALUE val)
{
+ VALUE ret = range_string_cover_internal(range, val);
+ if (!UNDEF_P(ret)) return ret;
return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
}
@@ -1919,6 +1756,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
@@ -1929,24 +1768,36 @@ range_include(VALUE range, VALUE val)
return rb_call_super(1, &val);
}
-static inline bool
-range_integer_edge_p(VALUE beg, VALUE end)
-{
- return (!NIL_P(rb_check_to_integer(beg, "to_int")) ||
- !NIL_P(rb_check_to_integer(end, "to_int")));
-}
-
-static inline bool
-range_string_range_p(VALUE beg, VALUE end)
+static VALUE
+range_string_cover_internal(VALUE range, VALUE val)
{
- return RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING);
-}
+ VALUE beg = RANGE_BEG(range);
+ VALUE end = RANGE_END(range);
+ int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
+ linear_object_p(beg) || linear_object_p(end);
-static inline VALUE
-range_include_fallback(VALUE beg, VALUE end, VALUE val)
-{
- if (NIL_P(beg) && NIL_P(end)) {
- if (linear_object_p(val)) return Qtrue;
+ if (nv ||
+ !NIL_P(rb_check_to_integer(beg, "to_int")) ||
+ !NIL_P(rb_check_to_integer(end, "to_int"))) {
+ return r_cover_p(range, beg, end, val);
+ }
+ else if (RB_TYPE_P(beg, T_STRING) || RB_TYPE_P(end, T_STRING)) {
+ if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING)) {
+ return r_cover_p(range, beg, end, val);
+ }
+ if (NIL_P(beg)) {
+ VALUE r = rb_funcall(val, id_cmp, 1, end);
+ if (NIL_P(r)) return Qfalse;
+ if (RANGE_EXCL(range)) {
+ return RBOOL(rb_cmpint(r, val, end) < 0);
+ }
+ return RBOOL(rb_cmpint(r, val, end) <= 0);
+ }
+ else if (NIL_P(end)) {
+ VALUE r = rb_funcall(beg, id_cmp, 1, val);
+ if (NIL_P(r)) return Qfalse;
+ return RBOOL(rb_cmpint(r, beg, val) <= 0);
+ }
}
if (NIL_P(beg) || NIL_P(end)) {
@@ -1964,14 +1815,20 @@ range_include_internal(VALUE range, VALUE val)
int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
linear_object_p(beg) || linear_object_p(end);
- if (nv || range_integer_edge_p(beg, end)) {
+ if (nv ||
+ !NIL_P(rb_check_to_integer(beg, "to_int")) ||
+ !NIL_P(rb_check_to_integer(end, "to_int"))) {
return r_cover_p(range, beg, end, val);
}
- else if (range_string_range_p(beg, end)) {
+ else if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING)) {
return rb_str_include_range_p(beg, end, val, RANGE_EXCL(range));
}
- return range_include_fallback(beg, end, val);
+ if (NIL_P(beg) || NIL_P(end)) {
+ rb_raise(rb_eTypeError, "cannot determine inclusion in beginless/endless ranges");
+ }
+
+ return Qundef;
}
static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
@@ -1998,7 +1855,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
@@ -2019,7 +1876,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
@@ -2035,7 +1892,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
@@ -2257,137 +2114,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;
- }
- }
-
- 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
- *
- * Note that the method wouldn't make any assumptions about the beginless
- * range being actually empty, even if its upper bound is the minimum
- * possible value of its type, so all this would return +true+:
- *
- * (...-Float::INFINITY).overlap?(...-Float::INFINITY) # => true
- * (..."").overlap?(..."") # => true
- * (...[]).overlap?(...[]) # => true
- *
- * Even if those ranges are effectively empty (no number can be smaller than
- * <tt>-Float::INFINITY</tt>), they are still considered overlapping
- * with themselves.
- *
- * 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)));
- }
-
- 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 (!NIL_P(self_beg) && !NIL_P(other_beg)) {
- VALUE cmp = rb_funcall(self_beg, id_cmp, 1, other_beg);
- if (NIL_P(cmp)) return Qfalse;
- /* if both begin values are equal, no more comparisons needed */
- if (rb_cmpint(cmp, self_beg, other_beg) == 0) return Qtrue;
+ else if (NIL_P(RANGE_BEG(range))) {
+ /* We are confident that the answer is Infinity. */
+ return DBL2NUM(HUGE_VAL);
}
- else if (NIL_P(self_beg) && NIL_P(other_beg)) {
- VALUE cmp = rb_funcall(self_end, id_cmp, 1, other_end);
- return RBOOL(!NIL_P(cmp));
+ else {
+ return rb_call_super(argc, argv);
}
-
- 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
@@ -2570,7 +2307,6 @@ range_overlap(VALUE range, VALUE other)
* - {Comparing}[rdoc-ref:Range@Methods+for+Comparing]
* - {Iterating}[rdoc-ref:Range@Methods+for+Iterating]
* - {Converting}[rdoc-ref:Range@Methods+for+Converting]
- * - {Methods for Working with JSON}[rdoc-ref:Range@Methods+for+Working+with+JSON]
*
* === Methods for Creating a \Range
*
@@ -2605,7 +2341,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
*
@@ -2613,16 +2349,6 @@ range_overlap(VALUE range, VALUE other)
* - #to_a (aliased as #entries): Returns elements of +self+ in an array.
* - #to_s: Returns a string representation of +self+ (uses #to_s).
*
- * === Methods for Working with \JSON
- *
- * - ::json_create: Returns a new \Range object constructed from the given object.
- * - #as_json: Returns a 2-element hash representing +self+.
- * - #to_json: Returns a \JSON string representing +self+.
- *
- * To make these methods available:
- *
- * require 'json/add/range'
- *
*/
void
@@ -2647,7 +2373,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);
@@ -2668,5 +2393,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 a1d0ca3400..65317a4a5f 100644
--- a/re.c
+++ b/re.c
@@ -88,9 +88,6 @@ static const char casetable[] = {
# error >>> "You lose. You will need a translation table for your character set." <<<
#endif
-// The process-global timeout for regexp matching
-rb_hrtime_t rb_reg_match_time_limit = 0;
-
int
rb_memcicmp(const void *x, const void *y, long len)
{
@@ -285,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
@@ -453,7 +451,7 @@ rb_reg_expr_str(VALUE str, const char *s, long len,
}
static VALUE
-rb_reg_desc(VALUE re)
+rb_reg_desc(const char *s, long len, VALUE re)
{
rb_encoding *enc = rb_enc_get(re);
VALUE str = rb_str_buf_new2("/");
@@ -466,11 +464,7 @@ rb_reg_desc(VALUE re)
else {
rb_enc_associate(str, rb_usascii_encoding());
}
-
- VALUE src_str = RREGEXP_SRC(re);
- rb_reg_expr_str(str, RSTRING_PTR(src_str), RSTRING_LEN(src_str), enc, resenc, '/');
- RB_GC_GUARD(src_str);
-
+ rb_reg_expr_str(str, s, len, enc, resenc, '/');
rb_str_buf_cat2(str, "/");
if (re) {
char opts[OPTBUF_SIZE];
@@ -529,7 +523,7 @@ rb_reg_inspect(VALUE re)
if (!RREGEXP_PTR(re) || !RREGEXP_SRC(re) || !RREGEXP_SRC_PTR(re)) {
return rb_any_to_s(re);
}
- return rb_reg_desc(re);
+ return rb_reg_desc(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), re);
}
static VALUE rb_reg_str_with_term(VALUE re, int term);
@@ -545,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@Interpolation+Mode]:
+ * {Regexp literal}[rdoc-ref:regexp.rdoc@Regexp+Literal]:
*
* r1 = Regexp.new(s0) # => /(?ix-m:ab+c)/
* r2 = /#{s0}/ # => /(?ix-m:ab+c)/
@@ -572,6 +566,8 @@ rb_reg_str_with_term(VALUE re, int term)
{
int options, opt;
const int embeddable = ONIG_OPTION_MULTILINE|ONIG_OPTION_IGNORECASE|ONIG_OPTION_EXTEND;
+ long len;
+ const UChar* ptr;
VALUE str = rb_str_buf_new2("(?");
char optbuf[OPTBUF_SIZE + 1]; /* for '-' */
rb_encoding *enc = rb_enc_get(re);
@@ -580,9 +576,8 @@ rb_reg_str_with_term(VALUE re, int term)
rb_enc_copy(str, re);
options = RREGEXP_PTR(re)->options;
- VALUE src_str = RREGEXP_SRC(re);
- const UChar *ptr = (UChar *)RSTRING_PTR(src_str);
- long len = RSTRING_LEN(src_str);
+ ptr = (UChar*)RREGEXP_SRC_PTR(re);
+ len = RREGEXP_SRC_LEN(re);
again:
if (len >= 4 && ptr[0] == '(' && ptr[1] == '?') {
int err = 1;
@@ -672,17 +667,15 @@ rb_reg_str_with_term(VALUE re, int term)
}
rb_enc_copy(str, re);
- RB_GC_GUARD(src_str);
-
return str;
}
-NORETURN(static void rb_reg_raise(const char *err, VALUE re));
+NORETURN(static void rb_reg_raise(const char *s, long len, const char *err, VALUE re));
static void
-rb_reg_raise(const char *err, VALUE re)
+rb_reg_raise(const char *s, long len, const char *err, VALUE re)
{
- VALUE desc = rb_reg_desc(re);
+ VALUE desc = rb_reg_desc(s, len, re);
rb_raise(rb_eRegexpError, "%s: %"PRIsVALUE, err, desc);
}
@@ -770,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
@@ -969,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;
}
@@ -1010,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;
@@ -1088,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);
}
@@ -1133,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;
}
@@ -1178,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
@@ -1259,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));
}
/*
@@ -1318,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);
}
@@ -1344,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);
}
/*
@@ -1431,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);
}
@@ -1459,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;
@@ -1584,25 +1595,24 @@ 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;
VALUE unescaped;
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);
- VALUE src_str = RREGEXP_SRC(re);
- const char *pattern = RSTRING_PTR(src_str);
-
- onig_errmsg_buffer err = "";
unescaped = rb_reg_preprocess(
- pattern, pattern + RSTRING_LEN(src_str), enc,
+ pattern, pattern + RREGEXP_SRC_LEN(re), enc,
&fixed_enc, err, 0);
if (NIL_P(unescaped)) {
@@ -1615,76 +1625,25 @@ 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(err, re);
+ rb_reg_raise(pattern, RREGEXP_SRC_LEN(re), err, re);
}
reg->timelimit = timelimit;
RB_GC_GUARD(unescaped);
- RB_GC_GUARD(src_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);
-
- switch (result) {
- case ONIG_MISMATCH:
- break;
- case ONIGERR_TIMEOUT:
- rb_raise(rb_eRegexpTimeoutError, "regexp match timeout");
- default: {
- onig_errmsg_buffer err = "";
- onig_error_code_to_str((UChar*)err, (int)result);
- rb_reg_raise(err, re);
- }
- }
- }
-
- return result;
+ onig_errmsg_buffer err = "";
+ return rb_reg_prepare_re0(re, str, err);
}
long
@@ -1718,58 +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,
- };
- struct re_registers regs = {0};
-
- OnigPosition result = rb_reg_onig_match(re, str, reg_onig_search, &args, &regs);
+ reg = rb_reg_prepare_re0(re, str, err);
+ tmpreg = reg != RREGEXP_PTR(re);
+ if (!tmpreg) RREGEXP(re)->usecnt++;
- 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);
+ }
}
- VALUE match = match_alloc(rb_cMatch);
- rb_matchext_t *rm = RMATCH_EXT(match);
- rm->regs = regs;
+ 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!
@@ -1779,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;
@@ -1798,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);
-
- if (rb_reg_onig_match(re, str, reg_onig_match, NULL, regs) == ONIG_MISMATCH) {
- rb_backref_set(Qnil);
- return false;
- }
+ RMATCH(match)->str = rb_str_new4(str);
- 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;
@@ -1952,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
@@ -2170,17 +2158,6 @@ match_ary_aref(VALUE match, VALUE idx, VALUE result)
* m['foo'] # => "h"
* m[:bar] # => "ge"
*
- * If multiple captures have the same name, returns the last matched
- * substring.
- *
- * m = /(?<foo>.)(?<foo>.+)/.match("hoge")
- * # => #<MatchData "hoge" foo:"h" foo:"oge">
- * m[:foo] #=> "oge"
- *
- * m = /\W(?<foo>.+)|\w(?<foo>.+)|(?<foo>.+)/.match("hoge")
- * #<MatchData "hoge" foo:nil foo:"oge" foo:nil>
- * m[:foo] #=> "oge"
- *
*/
static VALUE
@@ -2343,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+:
@@ -2364,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;
@@ -2383,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);
@@ -2420,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) # => {}
@@ -2519,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">
@@ -2537,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
@@ -2974,11 +2926,7 @@ escape_asis:
case '#':
if (extended_mode && !in_char_class) {
/* consume and ignore comment in extended regexp */
- while ((p < end) && ((c = *p++) != '\n')) {
- if ((c & 0x80) && !*encp && enc == rb_utf8_encoding()) {
- *encp = enc;
- }
- }
+ while ((p < end) && ((c = *p++) != '\n'));
break;
}
rb_str_buf_cat(buf, (char *)&c, 1);
@@ -3013,9 +2961,6 @@ escape_asis:
switch (c = *p++) {
default:
if (!(c & 0x80)) break;
- if (!*encp && enc == rb_utf8_encoding()) {
- *encp = enc;
- }
--p;
/* fallthrough */
case '\\':
@@ -3038,8 +2983,7 @@ escape_asis:
rb_str_buf_cat(buf, (char *)&c, 1);
}
break;
- }
- else {
+ } else {
/* potential change of extended option */
int invert = 0;
int local_extend = 0;
@@ -3071,8 +3015,7 @@ escape_asis:
int local_options = options;
if (local_extend == 1) {
local_options |= ONIG_OPTION_EXTEND;
- }
- else {
+ } else {
local_options &= ~ONIG_OPTION_EXTEND;
}
@@ -3082,8 +3025,7 @@ escape_asis:
local_options, 1);
if (ret < 0) return ret;
goto begin_scan;
- }
- else {
+ } else {
/* change extended flag for rest of expression */
extended_mode = local_extend == 1;
goto fallthrough;
@@ -3101,8 +3043,7 @@ escape_asis:
}
}
}
- }
- else if (!in_char_class && recurse) {
+ } else if (!in_char_class && recurse) {
parens++;
}
/* FALLTHROUGH */
@@ -3239,15 +3180,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,
@@ -3258,7 +3190,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");
@@ -3335,7 +3272,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);
@@ -3382,7 +3319,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);
@@ -3421,6 +3358,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;
}
@@ -3480,6 +3418,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
@@ -3530,6 +3470,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
@@ -3594,7 +3537,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">
@@ -3607,7 +3550,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:
@@ -3810,6 +3753,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) {
@@ -3824,13 +3773,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;
}
/*
@@ -3868,26 +3837,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);
- FL_SET_RAW(copy, FL_TEST_RAW(orig, KCODE_FIXED|REG_ENCODING_NONE));
-
- return copy;
-}
-
struct reg_init_args {
VALUE str;
VALUE timeout;
@@ -3918,7 +3867,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:
*
@@ -3930,8 +3879,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,
@@ -3951,20 +3898,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);
@@ -3976,10 +3920,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)) {
@@ -3990,6 +3934,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;
@@ -4001,13 +3949,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;
@@ -4138,6 +4093,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
@@ -4387,7 +4344,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
@@ -4561,7 +4518,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">
@@ -4610,9 +4567,12 @@ re_warn(const char *s)
rb_warn("%s", s);
}
+// The process-global timeout for regexp matching
+rb_hrtime_t rb_reg_match_time_limit = 0;
+
// This function is periodically called during regexp matching
-bool
-rb_reg_timeout_p(regex_t *reg, void *end_time_)
+void
+rb_reg_check_timeout(regex_t *reg, void *end_time_)
{
rb_hrtime_t *end_time = (rb_hrtime_t *)end_time_;
@@ -4637,12 +4597,10 @@ rb_reg_timeout_p(regex_t *reg, void *end_time_)
}
else {
if (*end_time < rb_hrtime_now()) {
- // Timeout has exceeded
- return true;
+ // timeout is exceeded
+ rb_raise(rb_eRegexpTimeoutError, "regexp match timeout");
}
}
-
- return false;
}
/*
@@ -4723,7 +4681,7 @@ rb_reg_timeout_get(VALUE re)
/*
* Document-class: Regexp
*
- * :include: doc/_regexp.rdoc
+ * :include: doc/regexp.rdoc
*/
void
@@ -4751,7 +4709,7 @@ Init_Regexp(void)
rb_cRegexp = rb_define_class("Regexp", rb_cObject);
rb_define_alloc_func(rb_cRegexp, rb_reg_s_alloc);
- rb_define_singleton_method(rb_cRegexp, "compile", rb_class_new_instance_pass_kw, -1);
+ rb_define_singleton_method(rb_cRegexp, "compile", rb_class_new_instance, -1);
rb_define_singleton_method(rb_cRegexp, "quote", rb_reg_s_quote, 1);
rb_define_singleton_method(rb_cRegexp, "escape", rb_reg_s_quote, 1);
rb_define_singleton_method(rb_cRegexp, "union", rb_reg_s_union_m, -2);
@@ -4817,7 +4775,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 7bba1455e3..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:
@@ -3395,7 +3382,7 @@ next_setup(Node* node, Node* next_node, regex_t* reg)
}
else if (type == NT_ENCLOSE) {
EncloseNode* en = NENCLOSE(node);
- if (en->type == ENCLOSE_MEMORY && !IS_ENCLOSE_CALLED(en)) {
+ if (en->type == ENCLOSE_MEMORY) {
node = en->target;
goto retry;
}
@@ -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 eb523e1ae5..fc131d2533 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 (p + ret > e) ret = (int)(e - p); // just for case
+ if (ret > (int)(e - p)) ret = (int)(e - p); // just for case
return ret;
}
else if (ONIGENC_MBCLEN_NEEDMORE_P(ret)) {
diff --git a/regexec.c b/regexec.c
index 22c1ad050d..d261a3cbc0 100644
--- a/regexec.c
+++ b/regexec.c
@@ -231,46 +231,22 @@ onig_get_capture_tree(OnigRegion* region)
}
#endif /* USE_CAPTURE_HISTORY */
-#ifdef USE_MATCH_CACHE
-
-/*
-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.
-*/
-
-static OnigPosition count_num_cache_opcodes_inner(
- const regex_t* reg,
- MemNumType current_repeat_mem, int lookaround_nesting,
- UChar** pp, long* num_cache_opcodes_ptr
-)
+#ifdef USE_CACHE_MATCH_OPT
+
+/* count number of jump-like opcodes for allocation of cache memory. */
+static OnigPosition
+count_num_cache_opcode(regex_t* reg, long* num, long* table_size)
{
- UChar* p = *pp;
- UChar* pend = reg->p + reg->used;
+ 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;
- long num_cache_opcodes = *num_cache_opcodes_ptr;
- OnigPosition result;
+
+ *num = 0;
+ *table_size = 0;
while (p < pend) {
switch (*p++) {
@@ -284,7 +260,7 @@ static OnigPosition count_num_cache_opcodes_inner(
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;
@@ -299,7 +275,7 @@ static OnigPosition count_num_cache_opcodes_inner(
GET_LENGTH_INC(len, p);
p += mb_len * len;
}
- break;
+ break;
case OP_EXACT1_IC:
len = enclen(enc, p, pend); p += len; break;
@@ -308,7 +284,7 @@ static OnigPosition count_num_cache_opcodes_inner(
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;
@@ -324,10 +300,10 @@ static OnigPosition count_num_cache_opcodes_inner(
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:
@@ -360,7 +336,7 @@ static OnigPosition count_num_cache_opcodes_inner(
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:
@@ -368,12 +344,7 @@ static OnigPosition count_num_cache_opcodes_inner(
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;
@@ -381,131 +352,91 @@ static OnigPosition count_num_cache_opcodes_inner(
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++;
- }
- result = count_num_cache_opcodes_inner(reg, repeat_mem, lookaround_nesting, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
+ if (reg->repeat_range[mem].lower == 0) {
+ *num += 1;
+ *table_size += 1;
}
- {
- OnigRepeatRange *repeat_range = &reg->repeat_range[repeat_mem];
- if (repeat_range->lower < repeat_range->upper) {
- num_cache_opcodes++;
- }
- }
+ 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;
+ }
+ {
+ 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) {
+ *table_size += 1;
+ }
+ current_mem = -1;
+ current_mem_num = 0;
}
- goto exit;
+ 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;
- }
- result = count_num_cache_opcodes_inner(reg, current_repeat_mem, lookaround_nesting + 1, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
- }
- 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;
- result = count_num_cache_opcodes_inner(reg, current_repeat_mem, lookaround_nesting + 1, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
- }
- 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;
- result = count_num_cache_opcodes_inner(reg, current_repeat_mem, lookaround_nesting + 1, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
- }
- break;
- case OP_PUSH_STOP_BT:
- if (lookaround_nesting != 0) {
- // A nested atomic grouping is found.
- goto impossible;
- }
- result = count_num_cache_opcodes_inner(reg, current_repeat_mem, -1, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
- }
- break;
case OP_POP_POS:
+ case OP_PUSH_POS_NOT:
case OP_FAIL_POS:
- case OP_FAIL_LOOK_BEHIND_NOT:
+ case OP_PUSH_STOP_BT:
case OP_POP_STOP_BT:
- goto exit;
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:
@@ -513,69 +444,32 @@ static OnigPosition count_num_cache_opcodes_inner(
break;
default:
- goto bytecode_error;
+ goto bytecode_error;
}
}
-exit:
- *pp = p;
- *num_cache_opcodes_ptr = num_cache_opcodes;
return 0;
fail:
- *num_cache_opcodes_ptr = num_cache_opcodes;
- return result;
-
-impossible:
- *num_cache_opcodes_ptr = NUM_CACHE_OPCODES_IMPOSSIBLE;
+ *num = NUM_CACHE_OPCODE_FAIL;
return 0;
bytecode_error:
return ONIGERR_UNDEFINED_BYTECODE;
}
-/* count the total number of cache opcodes for allocating a match cache buffer. */
-static OnigPosition
-count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
-{
- UChar* p = reg->p;
- *num_cache_opcodes_ptr = 0;
- OnigPosition result = count_num_cache_opcodes_inner(reg, -1, 0, &p, num_cache_opcodes_ptr);
- if (result == 0 && *num_cache_opcodes_ptr >= 0 && p != reg->p + reg->used) {
- return ONIGERR_UNDEFINED_BYTECODE;
- }
-
- return result;
-}
-
static OnigPosition
-init_cache_opcodes_inner(
- const regex_t* reg,
- MemNumType current_repeat_mem, int lookaround_nesting,
- OnigCacheOpcode** cache_opcodes_ptr, UChar** pp, long* num_cache_points_ptr
-)
+init_cache_index_table(regex_t* reg, OnigCacheIndex *table)
{
- UChar* p = *pp;
- UChar* pend = reg->p + reg->used;
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;
- long cache_point = *num_cache_points_ptr;
- OnigCacheOpcode *cache_opcodes = *cache_opcodes_ptr;
- OnigPosition result;
-
-# define INC_CACHE_OPCODES do {\
- cache_opcodes->addr = pbegin;\
- cache_opcodes->cache_point = cache_point;\
- cache_opcodes->outer_repeat_mem = current_repeat_mem;\
- cache_opcodes->num_cache_points_at_outer_repeat = 0;\
- cache_opcodes->num_cache_points_in_outer_repeat = 0;\
- cache_opcodes->lookaround_nesting = lookaround_nesting;\
- cache_opcodes->match_addr = NULL;\
- cache_point += lookaround_nesting != 0 ? 2 : 1;\
- cache_opcodes++;\
- } while (0)
while (p < pend) {
pbegin = p;
@@ -590,7 +484,7 @@ init_cache_opcodes_inner(
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;
@@ -605,7 +499,7 @@ init_cache_opcodes_inner(
GET_LENGTH_INC(len, p);
p += mb_len * len;
}
- break;
+ break;
case OP_EXACT1_IC:
len = enclen(enc, p, pend); p += len; break;
@@ -614,7 +508,7 @@ init_cache_opcodes_inner(
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;
@@ -630,12 +524,20 @@ init_cache_opcodes_inner(
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:
@@ -677,11 +579,7 @@ init_cache_opcodes_inner(
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;
@@ -689,112 +587,79 @@ init_cache_opcodes_inner(
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_mem = mem;
+ current_mem_num = num;
+ break;
+ case OP_REPEAT_INC:
+ case OP_REPEAT_INC_NG:
+ GET_MEMNUM_INC(mem, p);
{
- long num_cache_points_in_repeat = 0;
- long num_cache_points_at_repeat = cache_point;
- OnigCacheOpcode* cache_opcodes_in_repeat = cache_opcodes;
- result = init_cache_opcodes_inner(reg, repeat_mem, lookaround_nesting, &cache_opcodes, &p, &num_cache_points_in_repeat);
- if (result != 0) {
- goto fail;
- }
- 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 -= lookaround_nesting != 0 ? 2 : 1;
- }
- 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 + (lookaround_nesting != 0 ? 2 : 1)) * repeat_bounds;
- for (; cache_opcodes_in_repeat < cache_opcodes; cache_opcodes_in_repeat++) {
- cache_opcodes_in_repeat->num_cache_points_at_outer_repeat = num_cache_points_at_repeat;
- cache_opcodes_in_repeat->num_cache_points_in_outer_repeat = num_cache_points_in_repeat;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = mem;
+ table++;
}
+ 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:
- case OP_REPEAT_INC_NG:
- p += SIZE_MEMNUM;
- goto exit;
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:
- lookaround:
- {
- OnigCacheOpcode* cache_opcodes_in_lookaround = cache_opcodes;
- result = init_cache_opcodes_inner(reg, current_repeat_mem, lookaround_nesting + 1, &cache_opcodes, &p, &cache_point);
- if (result != 0) {
- goto fail;
- }
- UChar* match_addr = p - 1;
- for (; cache_opcodes_in_lookaround < cache_opcodes; cache_opcodes_in_lookaround++) {
- if (cache_opcodes_in_lookaround->match_addr == NULL) {
- cache_opcodes_in_lookaround->match_addr = match_addr;
- }
- }
- }
- break;
- case OP_PUSH_POS_NOT:
- p += SIZE_RELADDR;
- goto lookaround;
- case OP_PUSH_LOOK_BEHIND_NOT:
- p += SIZE_RELADDR;
- p += SIZE_LENGTH;
- goto lookaround;
- case OP_PUSH_STOP_BT:
- {
- OnigCacheOpcode* cache_opcodes_in_atomic = cache_opcodes;
- result = init_cache_opcodes_inner(reg, current_repeat_mem, -1, &cache_opcodes, &p, &cache_point);
- if (result != 0) {
- goto fail;
- }
- UChar* match_addr = p - 1;
- for (; cache_opcodes_in_atomic < cache_opcodes; cache_opcodes_in_atomic++) {
- if (cache_opcodes_in_atomic->match_addr == NULL) {
- cache_opcodes_in_atomic->match_addr = match_addr;
- }
- }
- }
- break;
case OP_POP_POS:
+ case OP_PUSH_POS_NOT:
case OP_FAIL_POS:
- case OP_FAIL_LOOK_BEHIND_NOT:
+ case OP_PUSH_STOP_BT:
case OP_POP_STOP_BT:
- goto exit;
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;
@@ -819,54 +684,33 @@ init_cache_opcodes_inner(
break;
default:
- goto bytecode_error;
+ goto bytecode_error;
}
}
-exit:
- *cache_opcodes_ptr = cache_opcodes;
- *pp = p;
- *num_cache_points_ptr = cache_point;
return 0;
-fail:
- return result;
-
unexpected_bytecode_error:
return ONIGERR_UNEXPECTED_BYTECODE;
bytecode_error:
return ONIGERR_UNDEFINED_BYTECODE;
}
-
-/* collect cache opcodes from the given regex program, and compute the total number of cache points. */
+#else /* USE_MATCH_CACHE */
static OnigPosition
-init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes_ptr, long* num_cache_points_ptr)
+count_num_cache_opcode(regex_t* reg, long* num, long* table_size)
{
- UChar* p = reg->p;
- *num_cache_points_ptr = 0;
- OnigPosition result = init_cache_opcodes_inner(reg, -1, 0, &cache_opcodes_ptr, &p, num_cache_points_ptr);
- if (result == 0 && p != reg->p + reg->used) {
- return ONIGERR_UNDEFINED_BYTECODE;
- }
-
- return result;
-}
-#else
-static OnigPosition
-count_num_cache_opcodes(regex_t* reg, long* num_cache_opcodes)
-{
- *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
@@ -982,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);
}
}
@@ -1029,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
@@ -1087,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 {\
@@ -1098,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
@@ -1133,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 */
@@ -1253,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;\
}\
}\
@@ -1359,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 ? 0 : 1) + item->num;
+ }
+
+ return range->base_num + range->inner_num * range->lower + (range->inner_num + 1) * (count - range->lower) + 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;\
@@ -1485,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) \
@@ -1505,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"); \
@@ -1554,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:\
@@ -1567,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:\
@@ -1587,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;\
}\
@@ -1609,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)
@@ -1670,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)
@@ -1687,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)
@@ -1747,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--;\
@@ -1764,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 */ \
@@ -1943,19 +1832,6 @@ 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
@@ -2167,7 +2043,7 @@ onig_print_statistics(FILE* f)
#ifdef ONIG_DEBUG_MATCH
-static const char *
+static char *
stack_type_str(int stack_type)
{
switch (stack_type) {
@@ -2189,97 +2065,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. */
@@ -2306,7 +2095,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
UChar *pkeep;
char *alloca_base;
char *xmalloc_base = NULL;
- OnigStackType *stk_alloc, *stk_base = NULL, *stk, *stk_end;
+ OnigStackType *stk_alloc, *stk_base, *stk, *stk_end;
OnigStackType *stkp; /* used as any purpose. */
OnigStackIndex si;
OnigStackIndex *repeat_stk;
@@ -2588,49 +2377,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 MATCH_CACHE_HIT ((void) 0)
-
-# 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; MATCH_CACHE_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);
@@ -2936,7 +2682,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
int mb_len;
DATA_ENSURE(1);
- mb_len = enclen_approx(encode, s, end);
+ mb_len = enclen(encode, s, end);
DATA_ENSURE(mb_len);
ss = s;
s += mb_len;
@@ -3041,7 +2787,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR) MOP_IN(OP_ANYCHAR);
DATA_ENSURE(1);
- n = enclen_approx(encode, s, end);
+ n = enclen(encode, s, end);
DATA_ENSURE(n);
if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
s += n;
@@ -3050,7 +2796,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_approx(encode, s, end);
+ n = enclen(encode, s, end);
DATA_ENSURE(n);
s += n;
MOP_OUT;
@@ -3058,9 +2804,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_approx(encode, s, end);
+ n = enclen(encode, s, end);
DATA_ENSURE(n);
if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
sprev = s;
@@ -3071,9 +2817,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_approx(encode, s, end);
+ n = enclen(encode, s, end);
if (n > 1) {
DATA_ENSURE(n);
sprev = s;
@@ -3089,17 +2835,11 @@ 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;
if (*p == *s) {
+ 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 + 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++;
-#endif
}
- n = enclen_approx(encode, s, end);
+ n = enclen(encode, s, end);
DATA_ENSURE(n);
if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
sprev = s;
@@ -3111,17 +2851,11 @@ 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;
if (*p == *s) {
+ 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 + 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++;
-#endif
}
- n = enclen_approx(encode, s, end);
+ n = enclen(encode, s, end);
if (n > 1) {
DATA_ENSURE(n);
sprev = s;
@@ -3144,7 +2878,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_approx(encode, s, end);
+ n = enclen(encode, s, end);
DATA_ENSURE(n);
if (ONIGENC_IS_MBC_NEWLINE_EX(encode, s, str, end, option, 0)) goto fail;
sprev = s;
@@ -3162,7 +2896,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_approx(encode, s, end);
+ n = enclen(encode, s, end);
if (n > 1) {
DATA_ENSURE(n);
sprev = s;
@@ -3449,8 +3183,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. */
- mem_start_stk[mem] = GET_STACK_INDEX(stkp);
STACK_PUSH_MEM_END(mem, s);
+ mem_start_stk[mem] = GET_STACK_INDEX(stkp);
MOP_OUT;
JUMP;
@@ -3504,7 +3238,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_approx(encode, sprev, end)) < s)
+ while (sprev + (len = enclen(encode, sprev, end)) < s)
sprev += len;
MOP_OUT;
@@ -3534,8 +3268,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, n, end);
- while (sprev + (len = enclen_approx(encode, sprev, end)) < s)
+ STRING_CMP_IC(case_fold_flag, pstart, &s, (int)n, end);
+ while (sprev + (len = enclen(encode, sprev, end)) < s)
sprev += len;
MOP_OUT;
@@ -3570,7 +3304,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_approx(encode, sprev, end)) < s)
+ while (sprev + (len = enclen(encode, sprev, end)) < s)
sprev += len;
p += (SIZE_MEMNUM * (tlen - i - 1));
@@ -3705,9 +3439,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",
@@ -3716,6 +3451,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;
+ int 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_table ,msa->num_cache_opcode);
+ }
+# endif
}
MOP_OUT;
JUMP;
@@ -3758,7 +3516,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;
@@ -3799,10 +3557,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;
@@ -3812,7 +3570,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;
@@ -3824,15 +3582,14 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_PUSH_IF_PEEK_NEXT) MOP_IN(OP_PUSH_IF_PEEK_NEXT);
GET_RELADDR_INC(addr, p);
- CHECK_MATCH_CACHE;
if (*p == *s) {
p++;
+ 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;
}
p++;
- INC_NUM_FAILS;
MOP_OUT;
JUMP;
@@ -3846,7 +3603,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);
}
}
@@ -3863,7 +3620,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;
}
@@ -3882,15 +3639,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
/* end of repeat. Nothing to do. */
}
else if (stkp->u.repeat.count >= reg->repeat_range[mem].lower) {
-#ifdef USE_MATCH_CACHE
if (*pbegin == OP_REPEAT_INC) {
-#undef MATCH_CACHE_HIT
-#define MATCH_CACHE_HIT stkp->u.repeat.count--;
- CHECK_MATCH_CACHE;
-#undef MATCH_CACHE_HIT
-#define MATCH_CACHE_HIT ((void) 0)
+ 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);
}
-#endif
STACK_PUSH_ALT(p, s, sprev, pkeep);
p = STACK_AT(si)->u.repeat.pcode; /* Don't use stkp after PUSH. */
}
@@ -3922,7 +3673,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);
}
@@ -4116,67 +3867,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 = %"PRIuSIZE" (length = %"PRIuSIZE")\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) + 1;
- 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
@@ -4196,30 +3927,25 @@ 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;
-
- timeout:
- STACK_SAVE;
- xfree(xmalloc_base);
- return ONIGERR_TIMEOUT;
}
@@ -4920,17 +4646,12 @@ 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)) {
@@ -5067,11 +4788,6 @@ 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;
@@ -5211,64 +4927,44 @@ onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
# ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
# define MATCH_AND_RETURN_CHECK(upper_range) \
r = match_at(reg, str, end, (upper_range), s, prev, &msa); \
- switch (r) { \
- case ONIG_MISMATCH: \
- break; \
- case ONIGERR_TIMEOUT: \
- goto timeout; \
- default: \
- if (r >= 0) { \
- if (! IS_FIND_LONGEST(reg->options)) { \
- goto match; \
- }\
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ if (! IS_FIND_LONGEST(reg->options)) {\
+ goto match;\
}\
- else goto finish; /* error */ \
+ }\
+ else goto finish; /* error */ \
}
# else
# define MATCH_AND_RETURN_CHECK(upper_range) \
r = match_at(reg, str, end, (upper_range), s, prev, &msa); \
- switch (r) { \
- case ONIG_MISMATCH: \
- break; \
- case ONIGERR_TIMEOUT: \
- goto timeout; \
- default: \
- if (r >= 0) { \
- goto match; \
- }\
- else goto finish; /* error */ \
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ goto match;\
+ }\
+ else goto finish; /* error */ \
}
# endif /* USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE */
#else
# ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
# define MATCH_AND_RETURN_CHECK(none) \
r = match_at(reg, str, end, s, prev, &msa);\
- switch (r) { \
- case ONIG_MISMATCH: \
- break; \
- case ONIGERR_TIMEOUT: \
- goto timeout; \
- default: \
- if (r >= 0) { \
- if (! IS_FIND_LONGEST(reg->options)) { \
- goto match; \
- } \
- } \
- else goto finish; /* error */ \
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ if (! IS_FIND_LONGEST(reg->options)) {\
+ goto match;\
+ }\
+ }\
+ else goto finish; /* error */ \
}
# else
# define MATCH_AND_RETURN_CHECK(none) \
r = match_at(reg, str, end, s, prev, &msa);\
- switch (r) { \
- case ONIG_MISMATCH: \
- break; \
- case ONIGERR_TIMEOUT: \
- goto timeout; \
- default: \
- if (r >= 0) { \
- goto match; \
- } \
- else goto finish; /* error */ \
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ goto match;\
+ }\
+ else goto finish; /* error */ \
}
# endif /* USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE */
#endif /* USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE */
@@ -5571,10 +5267,6 @@ onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
match:
MATCH_ARG_FREE(msa);
return s - str;
-
-timeout:
- MATCH_ARG_FREE(msa);
- return ONIGERR_TIMEOUT;
}
extern OnigPosition
diff --git a/regint.h b/regint.h
index 75abfba235..75073e6377 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) || \
@@ -154,14 +158,12 @@
#ifdef RUBY
# define CHECK_INTERRUPT_IN_MATCH_AT do { \
- msa->counter++; \
- if (msa->counter >= 128) { \
- msa->counter = 0; \
- if (rb_reg_timeout_p(reg, &msa->end_time)) { \
- goto timeout; \
- } \
- rb_thread_check_ints(); \
- } \
+ msa->counter++; \
+ if (msa->counter >= 128) { \
+ msa->counter = 0; \
+ rb_reg_check_timeout(reg, &msa->end_time); \
+ rb_thread_check_ints(); \
+ } \
} while(0)
# define onig_st_init_table st_init_table
# define onig_st_init_table_with_size st_init_table_with_size
@@ -317,13 +319,9 @@ RUBY_SYMBOL_EXPORT_BEGIN
#define ONIG_LAST_CODE_POINT (~((OnigCodePoint )0))
-#define PLATFORM_GET_INC_ARGUMENTS_ASSERT(val, type) \
- ((void)sizeof(char[2 * (sizeof(val) == sizeof(type)) - 1]))
-
#ifdef PLATFORM_UNALIGNED_WORD_ACCESS
# define PLATFORM_GET_INC(val,p,type) do{\
- PLATFORM_GET_INC_ARGUMENTS_ASSERT(val, type);\
val = *(type* )p;\
(p) += sizeof(type);\
} while(0)
@@ -331,10 +329,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
#else
# define PLATFORM_GET_INC(val,p,type) do{\
- PLATFORM_GET_INC_ARGUMENTS_ASSERT(val, type);\
- type platform_get_value;\
- xmemcpy(&platform_get_value, (p), sizeof(type));\
- val = platform_get_value;\
+ xmemcpy(&val, (p), sizeof(type));\
(p) += sizeof(type);\
} while(0)
@@ -875,25 +870,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 {
@@ -918,23 +903,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))
@@ -998,7 +976,7 @@ extern int onig_st_insert_strend(hash_table_type* table, const UChar* str_key, c
#ifdef RUBY
extern size_t onig_memsize(const regex_t *reg);
extern size_t onig_region_memsize(const struct re_registers *regs);
-bool rb_reg_timeout_p(regex_t *reg, void *end_time);
+void rb_reg_check_timeout(regex_t *reg, void *end_time);
#endif
RUBY_SYMBOL_EXPORT_END
diff --git a/regparse.c b/regparse.c
index 57ecd78dee..4ebd5f1c46 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,8 +5977,7 @@ 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));
- bbuf_free(cc->mbuf);
- cc->mbuf = inverted_buf;
+ cc->mbuf = inverted_buf; /* TODO: check what to do with buffer before inversion */
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 82f17f7dbc..0000000000
--- a/rjit.c
+++ /dev/null
@@ -1,501 +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;
-
-// Postponed job handle for triggering rjit_iseq_update_references
-static rb_postponed_job_handle_t rjit_iseq_update_references_pjob;
-
-// 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, "exec-mem-size")) {
- rjit_opt->exec_mem_size = atoi(s + 1);
- }
- else if (opt_match_arg(s, l, "call-threshold")) {
- rjit_opt->call_threshold = atoi(s + 1);
- }
- else if (opt_match_noarg(s, l, "stats")) {
- rjit_opt->stats = true;
- }
- else if (opt_match_noarg(s, l, "disable")) {
- rjit_opt->disable = true;
- }
- else if (opt_match_noarg(s, l, "trace")) {
- rjit_opt->trace = 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;
- }
- 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-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) ")"),
- M("--rjit-stats", "", "Enable collecting RJIT statistics"),
- M("--rjit-disable", "", "Disable RJIT for lazily enabling it with RubyVM::RJIT.enable"),
- M("--rjit-trace", "", "Allow TracePoint during JIT compilation"),
- M("--rjit-trace-exits", "", "Trace side exit locations"),
-#ifdef HAVE_LIBCAPSTONE
- M("--rjit-dump-disasm", "", "Dump all JIT code"),
-#endif
- {0}
-};
-#undef M
-
-struct rb_rjit_runtime_counters rb_rjit_counters = { 0 };
-
-extern VALUE rb_gc_enable(void);
-extern VALUE rb_gc_disable(void);
-extern uint64_t rb_vm_insns_count;
-
-// Disable GC, TracePoint, JIT, stats, and $!
-#define WITH_RJIT_ISOLATED_USING_PC(using_pc, 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; \
- \
- const VALUE *pc = NULL; \
- if (rb_rjit_opts.trace) { \
- pc = GET_EC()->cfp->pc; \
- if (!using_pc) GET_EC()->cfp->pc = 0; /* avoid crashing on calc_lineno */ \
- } \
- else global_hooks->events = 0; \
- \
- bool original_call_p = rb_rjit_call_p; \
- rb_rjit_call_p = false; \
- \
- rjit_stats_p = false; \
- uint64_t insns_count = rb_vm_insns_count; \
- \
- VALUE err = rb_errinfo(); \
- \
- stmt; \
- \
- rb_set_errinfo(err); \
- \
- rb_vm_insns_count = insns_count; \
- rjit_stats_p = rb_rjit_opts.stats; \
- \
- rb_rjit_call_p = (rjit_cancel_p ? false : original_call_p); \
- \
- if (rb_rjit_opts.trace) GET_EC()->cfp->pc = pc; \
- else global_hooks->events = rb_rjit_global_events; \
- \
- if (!was_disabled) rb_gc_enable(); \
-} while (0);
-#define WITH_RJIT_ISOLATED(stmt) WITH_RJIT_ISOLATED_USING_PC(false, stmt)
-
-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_trigger(rjit_iseq_update_references_pjob);
-}
-
-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_USING_PC(true, {
- 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_USING_PC(true, {
- 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;
- }
- rjit_iseq_update_references_pjob = rb_postponed_job_preregister(0, rjit_iseq_update_references, NULL);
- if (rjit_iseq_update_references_pjob == POSTPONED_JOB_HANDLE_INVALID) {
- rb_bug("Could not preregister postponed job for RJIT");
- }
- 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.disable;
- 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 26d1d67fb1..0000000000
--- a/rjit.h
+++ /dev/null
@@ -1,101 +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
-
-#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;
- // Size of executable memory block in MiB
- unsigned int exec_mem_size;
- // Number of calls to trigger JIT compilation
- unsigned int call_threshold;
- // Collect RJIT statistics
- bool stats;
- // Do not start RJIT until RJIT.enable is called
- bool disable;
- // Allow TracePoint during JIT compilation
- bool trace;
- // Trace side exit locations
- bool trace_exits;
- // Enable disasm of all JIT code
- bool dump_disasm;
- // Verify context objects
- bool verify_ctx;
-};
-
-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 12fc10c91e..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 JIT compilation after \--rjit-disable.
- def self.enable
- 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 e6d8d5da5c..0000000000
--- a/rjit_c.c
+++ /dev/null
@@ -1,542 +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 references
-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);
-extern uint64_t rb_vm_insns_count;
-
-#include "rjit_c.rbinc"
-
-#endif // USE_RJIT
diff --git a/rjit_c.h b/rjit_c.h
deleted file mode 100644
index 339dfc38fc..0000000000
--- a/rjit_c.h
+++ /dev/null
@@ -1,164 +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(
- 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 30a84abaa5..0000000000
--- a/rjit_c.rb
+++ /dev/null
@@ -1,1695 +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_no_warnings(shape, obj, id)
- _shape = shape.to_i
- shape_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_shape_get_next_no_warnings((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_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_vm_insns_count
- Primitive.cexpr! %q{ SIZET2NUM(rb_vm_insns_count) }
- 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::Array.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::Array.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::Array.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::Array.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)")],
- exec_mem_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), exec_mem_size)")],
- call_threshold: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), call_threshold)")],
- stats: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), stats)")],
- disable: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), disable)")],
- trace: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), trace)")],
- 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)")],
- )
- 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)"),
- 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)")],
- specific_storage: [CType::Pointer.new { CType::Pointer.new { CType::Immediate.parse("void") } }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), specific_storage)")],
- 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 48acf4396e..e1a53d5236 100644
--- a/ruby-runner.c
+++ b/ruby-runner.c
@@ -7,12 +7,15 @@
#include <sys/types.h>
#include <sys/stat.h>
-#ifdef _WIN32
-# error This feature is unnecessary on Windows in favor of SxS.
-#endif
-
#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)
{
@@ -29,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;
@@ -73,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;
@@ -80,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) {
@@ -93,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 611d887cee..c27f44edb3 100644
--- a/ruby.c
+++ b/ruby.c
@@ -22,7 +22,7 @@
# include <sys/cygwin.h>
#endif
-#if defined(LOAD_RELATIVE) && defined(HAVE_DLADDR)
+#if (defined(LOAD_RELATIVE) || defined(__MACH__)) && defined(HAVE_DLADDR)
# include <dlfcn.h>
#endif
@@ -53,8 +53,8 @@
#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 "ruby/encoding.h"
#include "ruby/thread.h"
@@ -105,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 */
@@ -118,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),
@@ -204,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)
{
@@ -217,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;
}
@@ -242,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"),
@@ -341,16 +286,14 @@ 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|...}[,...]", "",
@@ -359,13 +302,9 @@ usage(const char *name, int help, int highlight, int columns)
"enable or disable features. see below for available features"),
M("--external-encoding=encoding", ", --internal-encoding=encoding",
"specify the default external or internal character encoding"),
- M("--parser={parse.y|prism}", ", --parser=prism",
- "the parser used to parse Ruby code (experimental)"),
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[] = {
@@ -374,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")"),
@@ -383,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 (experimental, 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)
@@ -424,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
}
@@ -571,8 +518,6 @@ translit_char_bin(char *p, int from, int to)
#endif
#ifdef _WIN32
-# undef chdir
-# define chdir rb_w32_uchdir
# define UTF8_PATH 1
#endif
@@ -599,13 +544,17 @@ str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
void ruby_init_loadpath(void);
-#if defined(LOAD_RELATIVE)
+#if defined(LOAD_RELATIVE) || defined(__MACH__)
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;
@@ -676,6 +625,10 @@ runtime_libruby_path(void)
#define INITIAL_LOAD_PATH_MARK rb_intern_const("@gem_prelude_index")
VALUE ruby_archlibdir_path, ruby_prefix_path;
+#if defined(__MACH__)
+// A path to libruby.dylib itself or where it's statically linked to.
+VALUE rb_libruby_selfpath;
+#endif
void
ruby_init_loadpath(void)
@@ -683,6 +636,19 @@ ruby_init_loadpath(void)
VALUE load_path, archlibdir = 0;
ID id_initial_load_path_mark;
const char *paths = ruby_initial_load_paths;
+#if defined(LOAD_RELATIVE) || defined(__MACH__)
+ VALUE libruby_path = runtime_libruby_path();
+# if defined(__MACH__)
+ VALUE selfpath = libruby_path;
+# if defined(LOAD_RELATIVE)
+ selfpath = rb_str_dup(selfpath);
+# endif
+ rb_obj_hide(selfpath);
+ OBJ_FREEZE_RAW(selfpath);
+ rb_libruby_selfpath = selfpath;
+ rb_gc_register_address(&rb_libruby_selfpath);
+# endif
+#endif
#if defined LOAD_RELATIVE
#if !defined ENABLE_MULTIARCH
@@ -697,7 +663,7 @@ ruby_init_loadpath(void)
size_t baselen;
const char *p;
- sopath = runtime_libruby_path();
+ sopath = libruby_path;
libpath = RSTRING_PTR(sopath);
p = strrchr(libpath, '/');
@@ -818,10 +784,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;
@@ -878,9 +844,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);
@@ -894,26 +859,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) {
@@ -941,24 +894,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);
@@ -1022,7 +957,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;
}
@@ -1182,326 +1117,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);
- }
- else if (is_option_with_arg("parser", Qfalse, Qtrue)) {
- if (strcmp("prism", s) == 0) {
- (*rb_ruby_prism_ptr()) = true;
- rb_warn("The compiler based on the Prism parser is currently experimental and "
- "compatibility with the compiler based on parse.y "
- "is not yet complete. Please report any issues you "
- "find on the `ruby/prism` issue tracker.");
- }
- else if (strcmp("parse.y", s) == 0) {
- // default behavior
- }
- else {
- rb_raise(rb_eRuntimeError, "unknown parser %s", s);
- }
- }
-#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_YJIT || USE_RJIT
- FEATURE_SET(opt->features, FEATURE_BIT(jit));
-#else
- rb_warn("Ruby was built without JIT support");
-#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)
{
@@ -1560,12 +1175,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':
@@ -1602,10 +1270,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':
@@ -1657,8 +1334,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);
@@ -1666,7 +1342,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':
@@ -1681,7 +1379,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 '-':
@@ -1691,10 +1405,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':
@@ -1702,9 +1539,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:
@@ -1712,8 +1551,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
}
}
@@ -1763,26 +1611,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 (getenv("RUBY_FREE_AT_EXIT")) {
- rb_category_warn(RB_WARN_CATEGORY_EXPERIMENTAL, "Free at exit is experimental and may be unstable");
- rb_free_at_exit = true;
- }
-
-#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 */
@@ -1791,14 +1623,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);
@@ -1930,10 +1767,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
@@ -1964,118 +1798,12 @@ copy_str(VALUE str, rb_encoding *enc, bool intern)
return rb_enc_interned_str(RSTRING_PTR(str), RSTRING_LEN(str), enc);
}
-#if USE_YJIT
-// Check that an environment variable is set to a truthy value
-static bool
-env_var_truthy(const char *name)
-{
- const char *value = getenv(name);
-
- if (!value)
- return false;
- if (strcmp(value, "1") == 0)
- return true;
- if (strcmp(value, "true") == 0)
- return true;
- if (strcmp(value, "yes") == 0)
- return true;
-
- return false;
-}
-#endif
-
-rb_pid_t rb_fork_ruby(int *status);
-
-static rb_ast_t *
-process_script(ruby_cmdline_options_t *opt)
-{
- rb_ast_t *ast;
- VALUE parser = rb_parser_new();
-
- if (opt->dump & DUMP_BIT(yydebug)) {
- rb_parser_set_yydebug(parser, Qtrue);
- }
-
- if (opt->dump & DUMP_BIT(error_tolerant)) {
- rb_parser_error_tolerant(parser);
- }
-
- if (opt->e_script) {
- VALUE progname = rb_progname;
- rb_parser_set_context(parser, 0, TRUE);
-
- ruby_opt_init(opt);
- ruby_set_script_name(progname);
- rb_parser_set_options(parser, opt->do_print, opt->do_loop,
- opt->do_line, opt->do_split);
- ast = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
- }
- else {
- VALUE f;
- int xflag = opt->xflag;
- f = open_load_file(opt->script_name, &xflag);
- opt->xflag = xflag != 0;
- rb_parser_set_context(parser, 0, f == rb_stdin);
- ast = load_file(parser, opt->script_name, f, 1, opt);
- }
- if (!ast->body.root) {
- rb_ast_dispose(ast);
- return NULL;
- }
- return ast;
-}
-
-static void
-prism_script(ruby_cmdline_options_t *opt, pm_string_t *input, pm_options_t *options)
-{
- ruby_opt_init(opt);
-
- if (strcmp(opt->script, "-") == 0) {
- rb_warn("Prism support for streaming code from stdin is not currently supported");
- pm_string_constant_init(input, "", 0);
- pm_options_filepath_set(options, "-e");
- }
- else 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));
- }
-}
-
-static VALUE
-prism_dump_tree(pm_string_t *input, 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);
-
- pm_buffer_t output_buffer = { 0 };
-
- pm_prettyprint(&output_buffer, &parser, node);
-
- VALUE tree = rb_str_new(output_buffer.value, output_buffer.length);
-
- pm_buffer_free(&output_buffer);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-
- return tree;
-}
-
static VALUE
process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
{
- rb_ast_t *ast = NULL;
- pm_string_t pm_input = { 0 };
- pm_options_t pm_options = { 0 };
-
-#define dispose_result() \
- (ast ? rb_ast_dispose(ast) : (pm_string_free(&pm_input), pm_options_free(&pm_options)))
-
+ rb_ast_t *ast = 0;
+ VALUE parser;
+ VALUE script_name;
const rb_iseq_t *iseq;
rb_encoding *enc, *lenc;
#if UTF8_PATH
@@ -2106,7 +1834,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);
@@ -2153,7 +1881,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)
@@ -2164,31 +1907,27 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
if (!(FEATURE_SET_BITS(opt->features) & feature_jit_mask)) {
#if USE_YJIT
- if (!FEATURE_USED_P(opt->features, yjit) && env_var_truthy("RUBY_YJIT_ENABLE")) {
+ if (!FEATURE_USED_P(opt->features, yjit) && getenv("RUBY_YJIT_ENABLE")) {
FEATURE_SET(opt->features, FEATURE_BIT(yjit));
}
#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
if (FEATURE_SET_P(opt->features, yjit)) {
- bool rb_yjit_option_disable(void);
- opt->yjit = !rb_yjit_option_disable(); // set opt->yjit for Init_ruby_description() and calling rb_yjit_init()
+ 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;
@@ -2246,6 +1985,13 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
lenc = rb_locale_encoding();
rb_enc_associate(rb_progname, lenc);
rb_obj_freeze(rb_progname);
+ parser = rb_parser_new();
+ if (opt->dump & DUMP_BIT(yydebug)) {
+ rb_parser_set_yydebug(parser, Qtrue);
+ }
+ if (opt->dump & DUMP_BIT(error_tolerant)) {
+ rb_parser_error_tolerant(parser);
+ }
if (opt->ext.enc.name != 0) {
opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
}
@@ -2271,6 +2017,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
ienc = enc;
#endif
}
+ script_name = opt->script_name;
rb_enc_associate(opt->script_name, IF_UTF8_PATH(uenc, lenc));
#if UTF8_PATH
if (uenc != lenc) {
@@ -2335,10 +2082,13 @@ 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) {
+ if (opt->e_script) {
+ VALUE progname = rb_progname;
rb_encoding *eenc;
+ rb_parser_set_context(parser, 0, TRUE);
+
if (opt->src.enc.index >= 0) {
eenc = rb_enc_from_index(opt->src.enc.index);
}
@@ -2354,18 +2104,22 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
#endif
rb_enc_associate(opt->e_script, eenc);
- }
-
- if (!(*rb_ruby_prism_ptr())) {
- if (!(ast = process_script(opt))) return Qfalse;
+ ruby_opt_init(opt);
+ ruby_set_script_name(progname);
+ rb_parser_set_options(parser, opt->do_print, opt->do_loop,
+ opt->do_line, opt->do_split);
+ ast = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
}
else {
- prism_script(opt, &pm_input, &pm_options);
+ VALUE f;
+ 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);
}
ruby_set_script_name(opt->script_name);
- if ((dump & DUMP_BIT(yydebug)) && !(dump &= ~DUMP_BIT(yydebug))) {
- dispose_result();
- return Qtrue;
+ if (dump & DUMP_BIT(yydebug)) {
+ dump &= ~DUMP_BIT(yydebug);
+ if (!dump) return Qtrue;
}
if (opt->ext.enc.index >= 0) {
@@ -2385,7 +2139,12 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
rb_enc_set_default_internal(Qnil);
rb_stdio_set_default_encoding();
- opt->sflag = process_sflag(opt->sflag);
+ if (!ast->body.root) {
+ rb_ast_dispose(ast);
+ return Qfalse;
+ }
+
+ process_sflag(&opt->sflag);
opt->xflag = 0;
if (dump & DUMP_BIT(syntax)) {
@@ -2402,19 +2161,11 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
if (dump & (DUMP_BIT(parsetree)|DUMP_BIT(parsetree_with_comment))) {
- VALUE tree;
- if (ast) {
- int comment = dump & DUMP_BIT(parsetree_with_comment);
- tree = rb_parser_dump_tree(ast->body.root, comment);
- }
- else {
- tree = prism_dump_tree(&pm_input, &pm_options);
- }
- rb_io_write(rb_stdout, tree);
+ rb_io_write(rb_stdout, rb_parser_dump_tree(ast->body.root, dump & DUMP_BIT(parsetree_with_comment)));
rb_io_flush(rb_stdout);
dump &= ~DUMP_BIT(parsetree)&~DUMP_BIT(parsetree_with_comment);
if (!dump) {
- dispose_result();
+ rb_ast_dispose(ast);
return Qtrue;
}
}
@@ -2422,7 +2173,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
{
VALUE path = Qnil;
if (!opt->e_script && strcmp(opt->script, "-")) {
- path = rb_realpath_internal(Qnil, opt->script_name, 1);
+ path = rb_realpath_internal(Qnil, script_name, 1);
#if UTF8_PATH
if (uenc != lenc) {
path = str_conv_enc(path, uenc, lenc);
@@ -2433,19 +2184,12 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
}
- bool optimize = !(dump & DUMP_BIT(insns_without_opt));
-
- if (!ast) {
- iseq = rb_iseq_new_main_prism(&pm_input, &pm_options, path);
- }
- else {
- rb_binding_t *toplevel_binding;
- GetBindingPtr(rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING")),
- toplevel_binding);
- const struct rb_block *base_block = toplevel_context(toplevel_binding);
- iseq = rb_iseq_new_main(&ast->body, opt->script_name, path, vm_block_iseq(base_block), optimize);
- rb_ast_dispose(ast);
- }
+ rb_binding_t *toplevel_binding;
+ GetBindingPtr(rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING")),
+ toplevel_binding);
+ const struct rb_block *base_block = toplevel_context(toplevel_binding);
+ iseq = rb_iseq_new_main(&ast->body, opt->script_name, path, vm_block_iseq(base_block), !(dump & DUMP_BIT(insns_without_opt)));
+ rb_ast_dispose(ast);
}
if (dump & (DUMP_BIT(insns) | DUMP_BIT(insns_without_opt))) {
@@ -2456,10 +2200,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);
@@ -2510,8 +2250,6 @@ struct load_file_arg {
VALUE f;
};
-VALUE rb_script_lines_for(VALUE path, bool add);
-
static VALUE
load_file_internal(VALUE argp_v)
{
@@ -2614,12 +2352,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);
@@ -2783,9 +2515,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);
}
@@ -2860,18 +2590,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);
}
}
@@ -2882,7 +2606,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
@@ -3002,26 +2727,19 @@ ruby_process_options(int argc, char **argv)
VALUE iseq;
const char *script_name = (argc > 0 && argv[0]) ? argv[0] : ruby_engine;
- (*rb_ruby_prism_ptr()) = false;
-
if (!origarg.argv || origarg.argc <= 0) {
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 10286b51e7..0000000000
--- a/ruby_parser.c
+++ /dev/null
@@ -1,913 +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_coderange_broken = ENC_CODERANGE_BROKEN;
- 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->enc_str_coderange = rb_enc_str_coderange;
-
- 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 d1f499a060..0000000000
--- a/rubyparser.h
+++ /dev/null
@@ -1,1405 +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_REDO 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;
- int enc_coderange_broken;
- 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);
- int (*enc_str_coderange)(VALUE str);
-
- /* 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 0906bc0101..fb84e6b4dd 100644
--- a/scheduler.c
+++ b/scheduler.c
@@ -161,21 +161,6 @@ 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)
{
@@ -193,8 +178,7 @@ 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_ensure(fiber_scheduler_close, thread->scheduler, fiber_scheduler_close_ensure, (VALUE)thread);
+ rb_fiber_scheduler_close(thread->scheduler);
}
thread->scheduler = scheduler;
@@ -403,15 +387,7 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
{
VM_ASSERT(rb_obj_is_fiber(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;
+ return rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
}
/*
@@ -482,18 +458,19 @@ 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, 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+.
+ * Invoked by IO#read to read +length+ bytes from +io+ into a 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 +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.
+ * Specifying a +length+ of 0 is valid and means try reading at least once
+ * and return any available data.
*
* Suggested implementation should try to read from +io+ in a non-blocking
* manner and call #io_wait if the +io+ is not ready (which will yield control
@@ -501,8 +478,8 @@ VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
*
* See IO::Buffer for an interface available to return data.
*
- * Expected to return number of bytes read, or, in case of an error,
- * <tt>-errno</tt> (negated number corresponding to system's error code).
+ * Expected to return number of bytes read, or, in case of an error, <tt>-errno</tt>
+ * (negated number corresponding to system's error code).
*
* The method should be considered _experimental_.
*/
@@ -516,19 +493,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)
@@ -542,29 +513,28 @@ 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, 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+.
+ * Invoked by IO#write to write +length+ bytes to +io+ from
+ * 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 +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.
*
- * Specifying a +length+ of 0 is valid and means try writing at least once, as
- * much data as possible.
+ * Specifying a +length+ of 0 is valid and means try writing at least once,
+ * as much data as possible.
*
* Suggested implementation should try to write to +io+ in a non-blocking
* manner and call #io_wait if the +io+ is not ready (which will yield control
* to other fibers).
*
- * See IO::Buffer for an interface available to get data from buffer
- * efficiently.
+ * See IO::Buffer for an interface available to get data from buffer efficiently.
*
- * Expected to return number of bytes written, or, in case of an error,
- * <tt>-errno</tt> (negated number corresponding to system's error code).
+ * Expected to return number of bytes written, or, in case of an error, <tt>-errno</tt>
+ * (negated number corresponding to system's error code).
*
* The method should be considered _experimental_.
*/
@@ -582,15 +552,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
@@ -610,7 +572,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;
}
@@ -622,31 +585,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 d4e2c0f2bb..f3150127ff 100644
--- a/shape.c
+++ b/shape.c
@@ -1,333 +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/error.h"
-#include "internal/gc.h"
-#include "internal/object.h"
#include "internal/symbol.h"
#include "internal/variable.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];
-#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 {
- RUBY_ASSERT(redblack_left(tree) == LEAF || redblack_left(tree)->key < tree->key);
- RUBY_ASSERT(redblack_right(tree) == LEAF || redblack_right(tree)->key > tree->key);
-
- 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;
- }
-
- RUBY_ASSERT(left == LEAF || left->key < key);
- RUBY_ASSERT(right == LEAF || right->key > key);
-
- 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 new_key, new_left_key, new_right_key;
- rb_shape_t *new_value, *new_left_value, *new_right_value;
- redblack_node_t *new_left_left, *new_left_right, *new_right_left, *new_right_right;
-
- if (redblack_red_p(left) && redblack_red_p(redblack_left(left))) {
- new_right_key = key;
- new_right_value = value;
- new_right_right = right;
-
- new_key = left->key;
- new_value = redblack_value(left);
- new_right_left = redblack_right(left);
-
- new_left_key = redblack_left(left)->key;
- new_left_value = redblack_value(redblack_left(left));
-
- new_left_left = redblack_left(redblack_left(left));
- new_left_right = redblack_right(redblack_left(left));
- }
- else if (redblack_red_p(left) && redblack_red_p(redblack_right(left))) {
- new_right_key = key;
- new_right_value = value;
- new_right_right = right;
-
- new_left_key = left->key;
- new_left_value = redblack_value(left);
- new_left_left = redblack_left(left);
-
- new_key = redblack_right(left)->key;
- new_value = redblack_value(redblack_right(left));
- new_left_right = redblack_left(redblack_right(left));
- new_right_left = redblack_right(redblack_right(left));
- }
- else if (redblack_red_p(right) && redblack_red_p(redblack_left(right))) {
- new_left_key = key;
- new_left_value = value;
- new_left_left = left;
-
- new_right_key = right->key;
- new_right_value = redblack_value(right);
- new_right_right = redblack_right(right);
-
- new_key = redblack_left(right)->key;
- new_value = redblack_value(redblack_left(right));
- new_left_right = redblack_left(redblack_left(right));
- new_right_left = redblack_right(redblack_left(right));
- }
- else if (redblack_red_p(right) && redblack_red_p(redblack_right(right))) {
- new_left_key = key;
- new_left_value = value;
- new_left_left = left;
-
- new_key = right->key;
- new_value = redblack_value(right);
- new_left_right = redblack_left(right);
-
- new_right_key = redblack_right(right)->key;
- new_right_value = redblack_value(redblack_right(right));
- new_right_left = redblack_left(redblack_right(right));
- new_right_right = redblack_right(redblack_right(right));
- }
- else {
- return redblack_new(color, key, value, left, right);
- }
-
- RUBY_ASSERT(new_left_key < new_key);
- RUBY_ASSERT(new_right_key > new_key);
- RUBY_ASSERT(new_left_left == LEAF || new_left_left->key < new_left_key);
- RUBY_ASSERT(new_left_right == LEAF || new_left_right->key > new_left_key);
- RUBY_ASSERT(new_left_right == LEAF || new_left_right->key < new_key);
- RUBY_ASSERT(new_right_left == LEAF || new_right_left->key < new_right_key);
- RUBY_ASSERT(new_right_left == LEAF || new_right_left->key > new_key);
- RUBY_ASSERT(new_right_right == LEAF || new_right_right->key > new_right_key);
-
- return redblack_new(
- RED, new_key, new_value,
- redblack_new(BLACK, new_left_key, new_left_value, new_left_left, new_left_right),
- redblack_new(BLACK, new_right_key, new_right_value, new_right_left, new_right_right));
- }
-
- 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 {
- redblack_node_t *left, *right;
- if (key < tree->key) {
- left = redblack_insert_aux(redblack_left(tree), key, value);
- RUBY_ASSERT(left != LEAF);
- right = redblack_right(tree);
- RUBY_ASSERT(right == LEAF || right->key > tree->key);
- }
- else if (key > tree->key) {
- left = redblack_left(tree);
- RUBY_ASSERT(left == LEAF || left->key < tree->key);
- right = redblack_insert_aux(redblack_right(tree), key, value);
- RUBY_ASSERT(right != LEAF);
- }
- else {
- return tree;
- }
-
- return redblack_balance(
- redblack_color(tree),
- tree->key,
- redblack_value(tree),
- left,
- right
- );
- }
-}
-
-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;
}
@@ -338,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)) {
@@ -383,111 +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);
-
-#if RUBY_DEBUG
- if (shape->ancestor_index) {
- redblack_node_t *inserted_node = redblack_find(shape->ancestor_index, shape->edge_name);
- RUBY_ASSERT(inserted_node);
- RUBY_ASSERT(redblack_value(inserted_node) == shape);
- }
-#endif
- }
- 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:
- if (UNLIKELY(shape->next_iv_index >= shape->capacity)) {
- RUBY_ASSERT(shape->next_iv_index == shape->capacity);
- new_shape->capacity = (uint32_t)rb_malloc_grow_capa(shape->capacity, sizeof(VALUE));
- }
- RUBY_ASSERT(new_shape->capacity > shape->next_iv_index);
- 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_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;
@@ -496,71 +139,84 @@ 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);
-
- 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;
+ *variation_created = had_edges;
+
+ 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;
}
+static void
+move_iv(VALUE obj, ID id, attr_index_t from, attr_index_t to)
+{
+ switch(BUILTIN_TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ RCLASS_IVPTR(obj)[to] = RCLASS_IVPTR(obj)[from];
+ break;
+ case T_OBJECT:
+ RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ ROBJECT_IVPTR(obj)[to] = ROBJECT_IVPTR(obj)[from];
+ break;
+ default: {
+ struct gen_ivtbl *ivtbl;
+ rb_gen_ivtbl_get(obj, id, &ivtbl);
+ ivtbl->ivptr[to] = ivtbl->ivptr[from];
+ break;
+ }
+ }
+}
+
static rb_shape_t *
-remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
+remove_shape_recursive(VALUE obj, ID id, rb_shape_t * shape, VALUE * removed)
{
if (shape->parent_id == INVALID_SHAPE_ID) {
// We've hit the top of the shape tree and couldn't find the
@@ -569,29 +225,41 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
}
else {
if (shape->type == SHAPE_IVAR && shape->edge_name == id) {
- *removed_shape = shape;
-
+ // We've hit the edge we wanted to remove, return it's _parent_
+ // as the new parent while we go back down the stack.
+ attr_index_t index = shape->next_iv_index - 1;
+
+ switch(BUILTIN_TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ *removed = RCLASS_IVPTR(obj)[index];
+ break;
+ case T_OBJECT:
+ *removed = ROBJECT_IVPTR(obj)[index];
+ break;
+ default: {
+ struct gen_ivtbl *ivtbl;
+ rb_gen_ivtbl_get(obj, id, &ivtbl);
+ *removed = ivtbl->ivptr[index];
+ break;
+ }
+ }
return rb_shape_get_parent(shape);
}
else {
// This isn't the IV we want to remove, keep walking up.
- rb_shape_t *new_parent = remove_shape_recursive(rb_shape_get_parent(shape), id, removed_shape);
+ rb_shape_t * new_parent = remove_shape_recursive(obj, id, rb_shape_get_parent(shape), 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;
+ rb_shape_t * new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true);
+ 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);
}
- RUBY_ASSERT(new_child->capacity <= shape->capacity);
-
return new_child;
}
else {
@@ -603,63 +271,16 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
}
}
-bool
-rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE *removed)
+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 *removed_shape = NULL;
- rb_shape_t *new_shape = remove_shape_recursive(shape, id, &removed_shape);
+ rb_shape_t * new_shape = remove_shape_recursive(obj, id, shape, removed);
if (new_shape) {
- RUBY_ASSERT(removed_shape != NULL);
-
- if (UNLIKELY(new_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return false;
- }
-
- RUBY_ASSERT(new_shape->next_iv_index == shape->next_iv_index - 1);
-
- VALUE *ivptr;
- switch(BUILTIN_TYPE(obj)) {
- case T_CLASS:
- case T_MODULE:
- ivptr = RCLASS_IVPTR(obj);
- break;
- case T_OBJECT:
- ivptr = ROBJECT_IVPTR(obj);
- break;
- default: {
- struct gen_ivtbl *ivtbl;
- rb_gen_ivtbl_get(obj, id, &ivtbl);
- ivptr = ivtbl->as.shape.ivptr;
- break;
- }
- }
-
- *removed = ivptr[removed_shape->next_iv_index - 1];
-
- memmove(&ivptr[removed_shape->next_iv_index - 1], &ivptr[removed_shape->next_iv_index],
- ((new_shape->next_iv_index + 1) - removed_shape->next_iv_index) * sizeof(VALUE));
-
- // Re-embed objects when instances become small enough
- // This is necessary because YJIT assumes that objects with the same shape
- // have the same embeddedness for efficiency (avoid extra checks)
- if (BUILTIN_TYPE(obj) == T_OBJECT &&
- !RB_FL_TEST_RAW(obj, ROBJECT_EMBED) &&
- rb_obj_embedded_size(new_shape->next_iv_index) <= rb_gc_obj_slot_size(obj)) {
- RB_FL_SET_RAW(obj, ROBJECT_EMBED);
- memcpy(ROBJECT_IVPTR(obj), ivptr, new_shape->next_iv_index * sizeof(VALUE));
- xfree(ivptr);
- }
-
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);
@@ -667,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);
}
/*
@@ -695,20 +317,10 @@ rb_shape_get_next_iv_shape(rb_shape_t* shape, ID id)
return get_next_shape_internal(shape, id, SHAPE_IVAR, &dont_care, true);
}
-static inline rb_shape_t *
-shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
+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;
- }
-
-#if RUBY_DEBUG
- attr_index_t index;
- if (rb_shape_get_iv_index(shape, id, &index)) {
- rb_bug("rb_shape_get_next: trying to create ivar that already exists at index %u", index);
- }
-#endif
bool allow_new_shape = true;
@@ -718,7 +330,12 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
}
bool variation_created = false;
- rb_shape_t *new_shape = get_next_shape_internal(shape, id, SHAPE_IVAR, &variation_created, allow_new_shape);
+ 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) {
@@ -729,17 +346,6 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
if (variation_created) {
RCLASS_EXT(klass)->variation_count++;
- if (emit_warnings && 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,
- "The class %"PRIsVALUE" reached %d shape variations, instance variables accesses will be slower and memory usage increased.\n"
- "It is recommended to define instance variables in a consistent order, for instance by eagerly defining them all in the #initialize method.",
- rb_class_path(klass),
- SHAPE_MAX_VARIATIONS
- );
- }
- }
}
}
@@ -747,76 +353,22 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
}
rb_shape_t *
-rb_shape_get_next(rb_shape_t *shape, VALUE obj, ID id)
-{
- return shape_get_next(shape, obj, id, true);
-}
-
-rb_shape_t *
-rb_shape_get_next_no_warnings(rb_shape_t *shape, VALUE obj, ID id)
+rb_shape_transition_shape_capa(rb_shape_t* shape, uint32_t new_capacity)
{
- return shape_get_next(shape, obj, id, false);
+ 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);
+ new_shape->capacity = new_capacity;
+ return new_shape;
}
-// 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)
+rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t *value)
{
- 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);
-}
+ // It doesn't make sense to ask for the index of an IV that's stored
+ // on an object that is "too complex" as it uses a hash for storing IVs
+ RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
-static bool
-shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
-{
while (shape->parent_id != INVALID_SHAPE_ID) {
if (shape->edge_name == id) {
enum shape_type shape_type;
@@ -827,62 +379,64 @@ shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
RUBY_ASSERT(shape->next_iv_index > 0);
*value = shape->next_iv_index - 1;
return true;
+ case SHAPE_CAPACITY_CHANGE:
case SHAPE_ROOT:
+ case SHAPE_INITIAL_CAPACITY:
case SHAPE_T_OBJECT:
return false;
case SHAPE_OBJ_TOO_COMPLEX:
case SHAPE_FROZEN:
- rb_bug("Ivar should not exist on transition");
+ rb_bug("Ivar should not exist on transition\n");
}
}
-
shape = rb_shape_get_parent(shape);
}
-
return false;
}
-static bool
-shape_cache_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
+static rb_shape_t *
+shape_alloc(void)
{
- 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);
- *value = shape->next_iv_index - 1;
+ rb_vm_t *vm = GET_VM();
+ shape_id_t shape_id = vm->next_shape_id;
+ vm->next_shape_id++;
-#if RUBY_DEBUG
- attr_index_t shape_tree_index;
- RUBY_ASSERT(shape_get_iv_index(shape, id, &shape_tree_index));
- RUBY_ASSERT(shape_tree_index == *value);
-#endif
+ if (shape_id == MAX_SHAPE_ID) {
+ // TODO: Make an OutOfShapesError ??
+ rb_bug("Out of shapes\n");
+ }
- return true;
- }
+ return &GET_VM()->shape_list[shape_id];
+}
- /* Verify the cache is correct by checking that this instance variable
- * does not exist in the shape tree either. */
- RUBY_ASSERT(!shape_get_iv_index(shape, id, value));
- }
+rb_shape_t *
+rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id)
+{
+ rb_shape_t * shape = shape_alloc();
- return false;
+ shape->edge_name = edge_name;
+ shape->next_iv_index = 0;
+ shape->parent_id = parent_id;
+
+ return shape;
}
-bool
-rb_shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
+rb_shape_t *
+rb_shape_alloc_with_size_pool_index(ID edge_name, rb_shape_t * parent, uint8_t size_pool_index)
{
- // It doesn't make sense to ask for the index of an IV that's stored
- // on an object that is "too complex" as it uses a hash for storing IVs
- RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
+ 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;
+}
- if (!shape_cache_get_iv_index(shape, id, value)) {
- return shape_get_iv_index(shape, id, value);
- }
- return true;
+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);
}
-void
+MJIT_FUNC_EXPORTED void
rb_shape_set_shape(VALUE obj, rb_shape_t* shape)
{
rb_shape_set_shape_id(obj, rb_shape_id(shape));
@@ -909,35 +463,26 @@ rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shap
switch ((enum shape_type)dest_shape->type) {
case SHAPE_IVAR:
- case SHAPE_FROZEN:
if (!next_shape->edges) {
return NULL;
}
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_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;
}
@@ -947,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;
@@ -966,36 +505,46 @@ rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape)
switch ((enum shape_type)dest_shape->type) {
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->capacity * 2);
+ }
+
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;
}
+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);
+}
+
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;
}
@@ -1004,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;
@@ -1075,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;
@@ -1136,23 +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));
-}
-
-/* :nodoc: */
-static VALUE
-rb_shape_exhaust(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- int offset = argc == 1 ? NUM2INT(argv[0]) : 0;
- GET_SHAPE_TREE()->next_shape_id = MAX_SHAPE_ID - offset + 1;
- return Qnil;
-}
-
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)
@@ -1164,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;
}
@@ -1206,74 +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;
-
- // If mmap fails, then give up on the redblack tree cache.
- // We set the cache size such that the redblack node allocators think
- // the cache is full.
- if (GET_SHAPE_TREE()->shape_cache == MAP_FAILED) {
- GET_SHAPE_TREE()->shape_cache = 0;
- GET_SHAPE_TREE()->cache_size = REDBLACK_CACHE_SIZE;
- }
-#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);
}
@@ -1283,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));
}
@@ -1296,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);
}
@@ -1333,16 +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);
- rb_define_singleton_method(rb_cShape, "exhaust_shapes", rb_shape_exhaust, -1);
#endif
}
diff --git a/shape.h b/shape.h
index 5fee17ebd9..8df12d3fb1 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;
-# 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;
-# define SHAPE_ID_NUM_BITS 16
-
#endif
-typedef uint32_t redblack_id_t;
-
#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,53 +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
@@ -102,68 +78,77 @@ 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);
+}
+
+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);
}
-#endif
+
+#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_get_next_no_warnings(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,23 +158,23 @@ 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;
}
-static inline st_table *
+static inline struct rb_id_table *
ROBJECT_IV_HASH(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
- return (st_table *)ROBJECT(obj)->as.heap.ivptr;
+ RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID);
+ return (struct rb_id_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)) {
- return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj));
+ if (ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID) {
+ return (uint32_t)rb_id_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;
}
}
@@ -214,11 +199,25 @@ RBASIC_IV_COUNT(VALUE obj)
return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj))->next_iv_index;
}
+static inline uint32_t
+RCLASS_IV_COUNT(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
+ uint32_t ivc = rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_iv_index;
+ 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
RUBY_SYMBOL_EXPORT_BEGIN
diff --git a/signal.c b/signal.c
index bef3b2e537..04db34fc3d 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"
@@ -133,7 +132,7 @@ static const struct signals {
#ifdef SIGCONT
{"CONT", SIGCONT},
#endif
-#ifdef RUBY_SIGCHLD
+#if RUBY_SIGCHLD
{"CHLD", RUBY_SIGCHLD },
{"CLD", RUBY_SIGCHLD },
#endif
@@ -403,9 +402,6 @@ interrupt_init(int argc, VALUE *argv, VALUE self)
}
void rb_malloc_info_show_results(void); /* gc.c */
-#if defined(USE_SIGALTSTACK) || defined(_WIN32)
-static void reset_sigmask(int sig);
-#endif
void
ruby_default_signal(int sig)
@@ -416,9 +412,6 @@ ruby_default_signal(int sig)
rb_malloc_info_show_results();
signal(sig, SIG_DFL);
-#if defined(USE_SIGALTSTACK) || defined(_WIN32)
- reset_sigmask(sig);
-#endif
raise(sig);
}
@@ -515,6 +508,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
@@ -612,6 +608,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
@@ -634,7 +651,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);
}
@@ -690,14 +707,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
@@ -886,10 +924,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
@@ -961,38 +999,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
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();
}
@@ -1052,6 +1085,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)
@@ -1119,7 +1162,7 @@ default_handler(int sig)
#ifdef SIGUSR2
case SIGUSR2:
#endif
-#ifdef RUBY_SIGCHLD
+#if RUBY_SIGCHLD
case RUBY_SIGCHLD:
#endif
func = sighandler;
@@ -1187,6 +1230,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;
}
@@ -1337,7 +1383,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
@@ -1404,7 +1450,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)
{
@@ -1429,6 +1474,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)
{
@@ -1440,6 +1504,7 @@ ruby_sig_finalize(void)
}
}
+
int ruby_enable_coredump = 0;
/*
@@ -1470,10 +1535,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
@@ -1494,9 +1559,6 @@ Init_signal(void)
rb_alias(rb_eSignal, rb_intern_const("signm"), rb_intern_const("message"));
rb_define_method(rb_eInterrupt, "initialize", interrupt_init, -1);
- // It should be ready to call rb_signal_exec()
- VM_ASSERT(GET_THREAD()->pending_interrupt_queue);
-
/* At this time, there is no subthread. Then sigmask guarantee atomics. */
rb_disable_interrupt();
@@ -1539,8 +1601,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();
@@ -1561,5 +1623,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/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 7cfc12a6f6..5894b4aa12 100644
--- a/spec/bundler/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler/bundler_spec.rb
@@ -5,14 +5,9 @@ require "tmpdir"
RSpec.describe Bundler do
describe "#load_marshal" do
- it "is a private method and raises an error" do
- data = Marshal.dump(Bundler)
- expect { Bundler.load_marshal(data) }.to raise_error(NoMethodError, /private method [`']load_marshal' called/)
- end
-
it "loads any data" do
data = Marshal.dump(Bundler)
- expect(Bundler.send(:load_marshal, data)).to eq(Bundler)
+ expect(Bundler.load_marshal(data)).to eq(Bundler)
end
end
@@ -23,50 +18,10 @@ 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
-
- it "loads Gem::Specification" do
- gem_spec = Gem::Specification.new do |s|
- s.name = "bundler"
- s.version = Gem::Version.new("2.4.7")
- s.installed_by_version = Gem::Version.new("0")
- s.authors = ["André Arko",
- "Samuel Giddins",
- "Colby Swandale",
- "Hiroshi Shibata",
- "David Rodríguez",
- "Grey Baker",
- "Stephanie Morillo",
- "Chris Morris",
- "James Wen",
- "Tim Moore",
- "André Medeiros",
- "Jessica Lynn Suttles",
- "Terence Lee",
- "Carl Lerche",
- "Yehuda Katz"]
- s.date = Time.utc(2023, 2, 15)
- s.description = "Bundler manages an application's dependencies through its entire life, across many machines, systematically and repeatably"
- s.email = ["team@bundler.io"]
- s.homepage = "https://bundler.io"
- s.metadata = { "bug_tracker_uri" => "https://github.com/rubygems/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler",
- "changelog_uri" => "https://github.com/rubygems/rubygems/blob/master/bundler/CHANGELOG.md",
- "homepage_uri" => "https://bundler.io/",
- "source_code_uri" => "https://github.com/rubygems/rubygems/tree/master/bundler" }
- s.require_paths = ["lib"]
- s.required_ruby_version = Gem::Requirement.new([">= 2.6.0"])
- s.required_rubygems_version = Gem::Requirement.new([">= 3.0.1"])
- s.rubygems_version = "3.4.7"
- s.specification_version = 4
- s.summary = "The best way to manage your application's dependencies"
- s.license = false
- end
- data = Marshal.dump(gem_spec)
- expect(Bundler.safe_load_marshal(data)).to eq(gem_spec)
- end
end
describe "#load_gemspec_uncached" do
@@ -76,7 +31,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
@@ -88,7 +43,7 @@ RSpec.describe Bundler do
end
end
- context "with correct YAML file", if: defined?(Encoding) do
+ context "with correct YAML file", :if => defined?(Encoding) do
it "can load a gemspec with unicode characters with default ruby encoding" do
# spec_helper forces the external encoding to UTF-8 but that's not the
# default until Ruby 2.0
@@ -99,7 +54,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"
@@ -139,7 +94,7 @@ RSpec.describe Bundler do
end
GEMSPEC
end
- expect(Bundler.rubygems).to receive(:validate).with have_attributes(name: "validated")
+ expect(Bundler.rubygems).to receive(:validate).with have_attributes(:name => "validated")
subject
end
end
@@ -147,7 +102,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,17 +179,35 @@ 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
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
allow(Bundler).to receive(:root).and_return(bundled_app)
- Bundler.mkdir_p(bundled_app("foo", "bar"))
- expect(bundled_app("foo", "bar")).to exist
+ Bundler.mkdir_p(bundled_app.join("foo", "bar"))
+ expect(bundled_app.join("foo", "bar")).to exist
end
end
@@ -267,7 +240,6 @@ RSpec.describe Bundler do
it "should issue a warning and return a temporary user home" do
allow(Bundler.rubygems).to receive(:user_home).and_return(path)
allow(File).to receive(:directory?).with(path).and_return true
- allow(File).to receive(:writable?).and_call_original
allow(File).to receive(:writable?).with(path).and_return false
allow(File).to receive(:directory?).with(dotbundle).and_return false
allow(Bundler).to receive(:tmp).and_return(Pathname.new("/tmp/trulyrandom"))
diff --git a/spec/bundler/bundler/ci_detector_spec.rb b/spec/bundler/bundler/ci_detector_spec.rb
deleted file mode 100644
index 299d8005e8..0000000000
--- a/spec/bundler/bundler/ci_detector_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Bundler::CIDetector do
- # This is properly tested in rubygems, under the name Gem::CIDetector
- # But the test that confirms that our version _stays in sync_ with that version
- # will live here.
-
- it "stays in sync with the rubygems implementation" do
- rubygems_implementation_path = File.join(git_root, "lib", "rubygems", "ci_detector.rb")
- expect(File.exist?(rubygems_implementation_path)).to be_truthy
- rubygems_code = File.read(rubygems_implementation_path)
- denamespaced_rubygems_code = rubygems_code.sub("Gem", "NAMESPACE")
-
- bundler_implementation_path = File.join(source_lib_dir, "bundler", "ci_detector.rb")
- expect(File.exist?(bundler_implementation_path)).to be_truthy
- bundler_code = File.read(bundler_implementation_path)
- denamespaced_bundler_code = bundler_code.sub("Bundler", "NAMESPACE")
-
- expect(denamespaced_bundler_code).to eq(denamespaced_rubygems_code)
- end
-end
diff --git a/spec/bundler/bundler/cli_spec.rb b/spec/bundler/bundler/cli_spec.rb
index b2cc1ccfef..b752cd7e70 100644
--- a/spec/bundler/bundler/cli_spec.rb
+++ b/spec/bundler/bundler/cli_spec.rb
@@ -4,12 +4,12 @@ require "bundler/cli"
RSpec.describe "bundle executable" do
it "returns non-zero exit status when passed unrecognized options" do
- bundle "--invalid_argument", raise_on_error: false
+ bundle "--invalid_argument", :raise_on_error => false
expect(exitstatus).to_not be_zero
end
it "returns non-zero exit status when passed unrecognized task" do
- bundle "unrecognized-task", raise_on_error: false
+ bundle "unrecognized-task", :raise_on_error => false
expect(exitstatus).to_not be_zero
end
@@ -87,7 +87,7 @@ RSpec.describe "bundle executable" do
end
context "with no arguments" do
- it "prints a concise help message", bundler: "3" do
+ it "prints a concise help message", :bundler => "3" do
bundle ""
expect(err).to be_empty
expect(out).to include("Bundler version #{Bundler::VERSION}").
@@ -101,30 +101,30 @@ RSpec.describe "bundle executable" do
context "when ENV['BUNDLE_GEMFILE'] is set to an empty string" do
it "ignores it" do
gemfile bundled_app_gemfile, <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- bundle :install, env: { "BUNDLE_GEMFILE" => "" }
+ bundle :install, :env => { "BUNDLE_GEMFILE" => "" }
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
context "with --verbose" do
it "prints the running command" do
- gemfile "source 'https://gem.repo1'"
- bundle "info bundler", verbose: true
+ gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ bundle "info bundler", :verbose => true
expect(out).to start_with("Running `bundle info bundler --verbose` with bundler #{Bundler::VERSION}")
end
it "doesn't print defaults" do
- install_gemfile "source 'https://gem.repo1'", verbose: true
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", :verbose => true
expect(out).to start_with("Running `bundle install --verbose` with bundler #{Bundler::VERSION}")
end
it "doesn't print defaults" do
- install_gemfile "source 'https://gem.repo1'", verbose: true
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", :verbose => true
expect(out).to start_with("Running `bundle install --verbose` with bundler #{Bundler::VERSION}")
end
end
@@ -133,13 +133,13 @@ RSpec.describe "bundle executable" do
let(:run_command) do
bundle "install"
- bundle "outdated #{flags}", raise_on_error: false
+ bundle "outdated #{flags}", :raise_on_error => false
end
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", '0.9.1'
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", '0.9.1'
G
end
@@ -149,8 +149,8 @@ RSpec.describe "bundle executable" do
it "prints a message when there are outdated gems" do
run_command
- expect(out).to include("Gem Current Latest Requested Groups")
- expect(out).to include("myrack 0.9.1 1.0.0 = 0.9.1 default")
+ expect(out).to include("Gem Current Latest Requested Groups")
+ expect(out).to include("rack 0.9.1 1.0.0 = 0.9.1 default")
end
end
@@ -160,7 +160,7 @@ RSpec.describe "bundle executable" do
it "prints a message when there are outdated gems" do
run_command
- expect(out).to include("myrack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
+ expect(out).to include("rack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
end
end
@@ -170,7 +170,7 @@ RSpec.describe "bundle executable" do
it "prints a simplified message when there are outdated gems" do
run_command
- expect(out).to include("myrack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
+ expect(out).to include("rack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
end
end
end
@@ -178,7 +178,7 @@ RSpec.describe "bundle executable" do
describe "printing the outdated warning" do
shared_examples_for "no warning" do
it "prints no warning" do
- bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
+ bundle "fail", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
expect(last_command.stdboth).to eq("Could not find command \"fail\".")
end
end
@@ -213,7 +213,7 @@ RSpec.describe "bundle executable" do
context "when the latest version is greater than the current version" do
let(:latest_version) { "222.0" }
it "prints the version warning" do
- bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
+ bundle "fail", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
expect(err).to start_with(<<-EOS.strip)
The latest bundler is #{latest_version}, but you are currently running #{bundler_version}.
To update to the most recent version, run `bundle update --bundler`
@@ -221,16 +221,16 @@ To update to the most recent version, run `bundle update --bundler`
end
context "and disable_version_check is set" do
- before { bundle "config set disable_version_check true", env: { "BUNDLER_VERSION" => bundler_version } }
+ before { bundle "config set disable_version_check true", :env => { "BUNDLER_VERSION" => bundler_version } }
include_examples "no warning"
end
context "running a parseable command" do
it "prints no warning" do
- bundle "config get --parseable foo", env: { "BUNDLER_VERSION" => bundler_version }
+ bundle "config get --parseable foo", :env => { "BUNDLER_VERSION" => bundler_version }
expect(last_command.stdboth).to eq ""
- bundle "platform --ruby", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
+ bundle "platform --ruby", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
expect(last_command.stdboth).to eq "Could not locate Gemfile"
end
end
@@ -238,7 +238,7 @@ To update to the most recent version, run `bundle update --bundler`
context "and is a pre-release" do
let(:latest_version) { "222.0.0.pre.4" }
it "prints the version warning" do
- bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
+ bundle "fail", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
expect(err).to start_with(<<-EOS.strip)
The latest bundler is #{latest_version}, but you are currently running #{bundler_version}.
To update to the most recent version, run `bundle update --bundler`
@@ -250,12 +250,12 @@ To update to the most recent version, run `bundle update --bundler`
end
RSpec.describe "bundler executable" do
- it "shows the bundler version just as the `bundle` executable does", bundler: "< 3" do
+ it "shows the bundler version just as the `bundle` executable does", :bundler => "< 3" do
bundler "--version"
expect(out).to eq("Bundler version #{Bundler::VERSION}")
end
- it "shows the bundler version just as the `bundle` executable does", bundler: "3" do
+ it "shows the bundler version just as the `bundle` executable does", :bundler => "3" do
bundler "--version"
expect(out).to eq(Bundler::VERSION)
end
diff --git a/spec/bundler/bundler/compact_index_client/parser_spec.rb b/spec/bundler/bundler/compact_index_client/parser_spec.rb
deleted file mode 100644
index 1f6b9e593b..0000000000
--- a/spec/bundler/bundler/compact_index_client/parser_spec.rb
+++ /dev/null
@@ -1,237 +0,0 @@
-# frozen_string_literal: true
-
-require "bundler/compact_index_client"
-require "bundler/compact_index_client/parser"
-
-TestCompactIndexClient = Struct.new(:names, :versions, :info_data) do
- # Requiring the checksum to match the input data helps ensure
- # that we are parsing the correct checksum from the versions file
- def info(name, checksum)
- info_data.dig(name, checksum)
- end
-
- def set_info_data(name, value)
- info_data[name] = value
- end
-end
-
-RSpec.describe Bundler::CompactIndexClient::Parser do
- subject(:parser) { described_class.new(compact_index) }
-
- let(:compact_index) { TestCompactIndexClient.new(names, versions, info_data) }
- let(:names) { "a\nb\nc\n" }
- let(:versions) { <<~VERSIONS.dup }
- created_at: 2024-05-01T00:00:04Z
- ---
- a 1.0.0,1.0.1,1.1.0 aaa111
- b 2.0.0,2.0.0-java bbb222
- c 3.0.0,3.0.3,3.3.3 ccc333
- c -3.0.3 ccc333yanked
- VERSIONS
- let(:info_data) do
- {
- "a" => { "aaa111" => a_info },
- "b" => { "bbb222" => b_info },
- "c" => { "ccc333yanked" => c_info },
- }
- end
- let(:a_info) { <<~INFO.dup }
- ---
- 1.0.0 |checksum:aaa1,ruby:>= 3.0.0,rubygems:>= 3.2.3
- 1.0.1 |checksum:aaa2,ruby:>= 3.0.0,rubygems:>= 3.2.3
- 1.1.0 |checksum:aaa3,ruby:>= 3.0.0,rubygems:>= 3.2.3
- INFO
- let(:b_info) { <<~INFO }
- 2.0.0 a:~> 1.0&<= 3.0|checksum:bbb1
- 2.0.0-java a:~> 1.0&<= 3.0|checksum:bbb2
- INFO
- let(:c_info) { <<~INFO }
- 3.0.0 a:= 1.0.0,b:~> 2.0|checksum:ccc1,ruby:>= 2.7.0,rubygems:>= 3.0.0
- 3.3.3 a:>= 1.1.0,b:~> 2.0|checksum:ccc3,ruby:>= 3.0.0,rubygems:>= 3.2.3
- INFO
-
- describe "#available?" do
- it "returns true versions are available" do
- expect(parser).to be_available
- end
-
- it "returns true when versions has only one gem" do
- compact_index.versions = +"a 1.0.0 aaa1\n"
- expect(parser).to be_available
- end
-
- it "returns true when versions has a gem and a header" do
- compact_index.versions = +"---\na 1.0.0 aaa1\n"
- expect(parser).to be_available
- end
-
- it "returns true when versions has a gem and a header with header data" do
- compact_index.versions = +"created_at: 2024-05-01T00:00:04Z\n---\na 1.0.0 aaa1\n"
- expect(parser).to be_available
- end
-
- it "returns false when versions has only the header" do
- compact_index.versions = +"---\n"
- expect(parser).not_to be_available
- end
-
- it "returns false when versions has only the header with header data" do
- compact_index.versions = +"created_at: 2024-05-01T00:00:04Z\n---\n"
- expect(parser).not_to be_available
- end
-
- it "returns false when versions index is not available" do
- compact_index.versions = nil
- expect(parser).not_to be_available
- end
-
- it "returns false when versions is empty" do
- compact_index.versions = +""
- expect(parser).not_to be_available
- end
- end
-
- describe "#names" do
- it "returns the names" do
- expect(parser.names).to eq(%w[a b c])
- end
-
- it "returns an empty array when names is empty" do
- compact_index.names = ""
- expect(parser.names).to eq([])
- end
-
- it "returns an empty array when names is not readable" do
- compact_index.names = nil
- expect(parser.names).to eq([])
- end
- end
-
- describe "#versions" do
- it "returns the versions" do
- expect(parser.versions).to eq(
- "a" => [
- ["a", "1.0.0"],
- ["a", "1.0.1"],
- ["a", "1.1.0"],
- ],
- "b" => [
- ["b", "2.0.0"],
- ["b", "2.0.0", "java"],
- ],
- "c" => [
- ["c", "3.0.0"],
- ["c", "3.3.3"],
- ],
- )
- end
-
- it "returns an empty hash when versions is empty" do
- compact_index.versions = ""
- expect(parser.versions).to eq({})
- end
-
- it "returns an empty hash when versions is not readable" do
- compact_index.versions = nil
- expect(parser.versions).to eq({})
- end
- end
-
- describe "#info" do
- let(:a_result) do
- [
- [
- "a",
- "1.0.0",
- nil,
- [],
- [["checksum", ["aaa1"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
- ],
- [
- "a",
- "1.0.1",
- nil,
- [],
- [["checksum", ["aaa2"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
- ],
- [
- "a",
- "1.1.0",
- nil,
- [],
- [["checksum", ["aaa3"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
- ],
- ]
- end
- let(:b_result) do
- [
- [
- "b",
- "2.0.0",
- nil,
- [["a", ["~> 1.0", "<= 3.0"]]],
- [["checksum", ["bbb1"]]],
- ],
- [
- "b",
- "2.0.0",
- "java",
- [["a", ["~> 1.0", "<= 3.0"]]],
- [["checksum", ["bbb2"]]],
- ],
- ]
- end
- let(:c_result) do
- [
- [
- "c",
- "3.0.0",
- nil,
- [["a", ["= 1.0.0"]], ["b", ["~> 2.0"]]],
- [["checksum", ["ccc1"]], ["ruby", [">= 2.7.0"]], ["rubygems", [">= 3.0.0"]]],
- ],
- [
- "c",
- "3.3.3",
- nil,
- [["a", [">= 1.1.0"]], ["b", ["~> 2.0"]]],
- [["checksum", ["ccc3"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
- ],
- ]
- end
-
- it "returns the info for example gem 'a' which has no deps" do
- expect(parser.info("a")).to eq(a_result)
- end
-
- it "returns the info for example gem 'b' which has platform and compound deps" do
- expect(parser.info("b")).to eq(b_result)
- end
-
- it "returns the info for example gem 'c' which has deps and yanked version (requires use of correct info checksum)" do
- expect(parser.info("c")).to eq(c_result)
- end
-
- it "returns an empty array when the info is empty" do
- compact_index.set_info_data("a", {})
- expect(parser.info("a")).to eq([])
- end
-
- it "returns an empty array when the info is not readable" do
- expect(parser.info("d")).to eq([])
- end
-
- it "handles empty lines in the versions file (Artifactory bug that they have yet to fix)" do
- compact_index.versions = +<<~VERSIONS
- created_at: 2024-05-01T00:00:04Z
- ---
- a 1.0.0,1.0.1,1.1.0 aaa111
- b 2.0.0,2.0.0-java bbb222
-
- c 3.0.0,3.0.3,3.3.3 ccc333
- c -3.0.3 ccc333yanked
- VERSIONS
- expect(parser.info("a")).to eq(a_result)
- end
- end
-end
diff --git a/spec/bundler/bundler/compact_index_client/updater_spec.rb b/spec/bundler/bundler/compact_index_client/updater_spec.rb
index 6eed88ca9e..fe417e3920 100644
--- a/spec/bundler/bundler/compact_index_client/updater_spec.rb
+++ b/spec/bundler/bundler/compact_index_client/updater_spec.rb
@@ -1,224 +1,43 @@
# frozen_string_literal: true
-require "bundler/vendored_net_http"
+require "net/http"
require "bundler/compact_index_client"
require "bundler/compact_index_client/updater"
require "tmpdir"
RSpec.describe Bundler::CompactIndexClient::Updater do
- subject(:updater) { described_class.new(fetcher) }
-
let(:fetcher) { double(:fetcher) }
- let(:local_path) { Pathname.new(Dir.mktmpdir("localpath")).join("versions") }
- let(:etag_path) { Pathname.new(Dir.mktmpdir("localpath-etags")).join("versions.etag") }
+ let(:local_path) { Pathname.new Dir.mktmpdir("localpath") }
let(:remote_path) { double(:remote_path) }
- let(:full_body) { "abc123" }
- let(:response) { double(:response, body: full_body, is_a?: false) }
- let(:digest) { Digest::SHA256.base64digest(full_body) }
-
- context "when the local path does not exist" do
- before do
- allow(response).to receive(:[]).with("Repr-Digest") { nil }
- allow(response).to receive(:[]).with("Digest") { nil }
- allow(response).to receive(:[]).with("ETag") { '"thisisanetag"' }
- end
-
- it "downloads the file without attempting append" do
- expect(fetcher).to receive(:call).once.with(remote_path, {}) { response }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("thisisanetag")
- end
-
- it "fails immediately on bad checksum" do
- expect(fetcher).to receive(:call).once.with(remote_path, {}) { response }
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
-
- expect do
- updater.update(remote_path, local_path, etag_path)
- end.to raise_error(Bundler::CompactIndexClient::Updater::MismatchedChecksumError)
- end
- end
-
- context "when the local path exists" do
- let(:local_body) { "abc" }
-
- before do
- local_path.open("w") {|f| f.write(local_body) }
- end
-
- context "with an etag" do
- before do
- etag_path.open("w") {|f| f.write("LocalEtag") }
- end
-
- let(:headers) do
- {
- "If-None-Match" => '"LocalEtag"',
- "Range" => "bytes=2-",
- }
- end
-
- it "does nothing if etags match" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { true }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq("abc")
- expect(etag_path.read).to eq("LocalEtag")
- end
-
- it "appends the file if etags do not match" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(response).to receive(:[]).with("ETag") { '"NewEtag"' }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
- allow(response).to receive(:body) { "c123" }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("NewEtag")
- end
-
- it "replaces the file if response ignores range" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(response).to receive(:[]).with("ETag") { '"NewEtag"' }
- allow(response).to receive(:body) { full_body }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("NewEtag")
- end
-
- it "tries the request again if the partial response fails digest check" do
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
- allow(response).to receive(:body) { "the beginning of the file changed" }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
-
- full_response = double(:full_response, body: full_body, is_a?: false)
- allow(full_response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(full_response).to receive(:[]).with("ETag") { '"NewEtag"' }
- expect(fetcher).to receive(:call).once.with(remote_path, { "If-None-Match" => '"LocalEtag"' }).and_return(full_response)
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("NewEtag")
- end
- end
-
- context "without an etag file" do
- let(:headers) do
- {
- "Range" => "bytes=2-",
- # This MD5 feature should be deleted after sufficient time has passed since release.
- # From then on, requests that still don't have a saved etag will be made without this header.
- "If-None-Match" => %("#{Digest::MD5.hexdigest(local_body)}"),
- }
- end
-
- it "saves only the etag_path if generated etag matches" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { true }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq("abc")
- expect(%("#{etag_path.read}")).to eq(headers["If-None-Match"])
- end
-
- it "appends the file" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(response).to receive(:[]).with("ETag") { '"OpaqueEtag"' }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
- allow(response).to receive(:body) { "c123" }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("OpaqueEtag")
- end
-
- it "replaces the file on full file response that ignores range request" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:[]).with("Repr-Digest") { nil }
- allow(response).to receive(:[]).with("Digest") { nil }
- allow(response).to receive(:[]).with("ETag") { '"OpaqueEtag"' }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
- allow(response).to receive(:body) { full_body }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("OpaqueEtag")
- end
-
- it "tries the request again if the partial response fails digest check" do
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
- allow(response).to receive(:body) { "the beginning of the file changed" }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
- expect(fetcher).to receive(:call).once.with(remote_path, headers) do
- # During the failed first request, we simulate another process writing the etag.
- # This ensures the second request doesn't generate the md5 etag again but just uses whatever is written.
- etag_path.open("w") {|f| f.write("LocalEtag") }
- response
- end
-
- full_response = double(:full_response, body: full_body, is_a?: false)
- allow(full_response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(full_response).to receive(:[]).with("ETag") { '"NewEtag"' }
- expect(fetcher).to receive(:call).once.with(remote_path, { "If-None-Match" => '"LocalEtag"' }).and_return(full_response)
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("NewEtag")
- end
- end
- end
+ let!(:updater) { described_class.new(fetcher) }
context "when the ETag header is missing" do
# Regression test for https://github.com/rubygems/bundler/issues/5463
- let(:response) { double(:response, body: full_body) }
+ let(:response) { double(:response, :body => "abc123") }
it "treats the response as an update" do
- allow(response).to receive(:[]).with("Repr-Digest") { nil }
- allow(response).to receive(:[]).with("Digest") { nil }
- allow(response).to receive(:[]).with("ETag") { nil }
+ expect(response).to receive(:[]).with("ETag") { nil }
expect(fetcher).to receive(:call) { response }
- updater.update(remote_path, local_path, etag_path)
+ updater.update(local_path, remote_path)
end
end
context "when the download is corrupt" do
- let(:response) { double(:response, body: "") }
+ let(:response) { double(:response, :body => "") }
it "raises HTTPError" do
expect(fetcher).to receive(:call).and_raise(Zlib::GzipFile::Error)
expect do
- updater.update(remote_path, local_path, etag_path)
+ updater.update(local_path, remote_path)
end.to raise_error(Bundler::HTTPError)
end
end
context "when receiving non UTF-8 data and default internal encoding set to ASCII" do
- let(:response) { double(:response, body: "\x8B".b) }
+ let(:response) { double(:response, :body => "\x8B".b) }
it "works just fine" do
old_verbose = $VERBOSE
@@ -227,12 +46,10 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
begin
$VERBOSE = false
Encoding.default_internal = "ASCII"
- allow(response).to receive(:[]).with("Repr-Digest") { nil }
- allow(response).to receive(:[]).with("Digest") { nil }
- allow(response).to receive(:[]).with("ETag") { nil }
+ expect(response).to receive(:[]).with("ETag") { nil }
expect(fetcher).to receive(:call) { response }
- updater.update(remote_path, local_path, etag_path)
+ updater.update(local_path, remote_path)
ensure
Encoding.default_internal = previous_internal_encoding
$VERBOSE = old_verbose
diff --git a/spec/bundler/bundler/definition_spec.rb b/spec/bundler/bundler/definition_spec.rb
index 6f8b24e68a..372fa2d5e2 100644
--- a/spec/bundler/bundler/definition_spec.rb
+++ b/spec/bundler/bundler/definition_spec.rb
@@ -5,60 +5,58 @@ require "bundler/definition"
RSpec.describe Bundler::Definition do
describe "#lock" do
before do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile) { bundled_app_gemfile }
- allow(Bundler).to receive(:ui) { double("UI", info: "", debug: "") }
+ allow(Bundler).to receive(:settings) { Bundler::Settings.new(".") }
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile) { Pathname.new("Gemfile") }
+ allow(Bundler).to receive(:ui) { double("UI", :info => "", :debug => "") }
end
-
- subject { Bundler::Definition.new(bundled_app_lock, [], Bundler::SourceList.new, {}) }
-
context "when it's not possible to write to the file" do
+ subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
+
it "raises an PermissionError with explanation" do
allow(File).to receive(:open).and_call_original
- expect(File).to receive(:open).with(bundled_app_lock, "wb").
+ expect(File).to receive(:open).with("Gemfile.lock", "wb").
and_raise(Errno::EACCES)
- expect { subject.lock }.
+ expect { subject.lock("Gemfile.lock") }.
to raise_error(Bundler::PermissionError, /Gemfile\.lock/)
end
end
context "when a temporary resource access issue occurs" do
+ subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
+
it "raises a TemporaryResourceError with explanation" do
allow(File).to receive(:open).and_call_original
- expect(File).to receive(:open).with(bundled_app_lock, "wb").
+ expect(File).to receive(:open).with("Gemfile.lock", "wb").
and_raise(Errno::EAGAIN)
- expect { subject.lock }.
+ expect { subject.lock("Gemfile.lock") }.
to raise_error(Bundler::TemporaryResourceError, /temporarily unavailable/)
end
end
context "when Bundler::Definition.no_lock is set to true" do
+ subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
before { Bundler::Definition.no_lock = true }
after { Bundler::Definition.no_lock = false }
it "does not create a lock file" do
- subject.lock
- expect(bundled_app_lock).not_to be_file
+ subject.lock("Gemfile.lock")
+ expect(File.file?("Gemfile.lock")).to eq false
end
end
end
describe "detects changes" do
it "for a path gem with changes" do
- build_lib "foo", "1.0", path: lib_path("foo")
+ build_lib "foo", "1.0", :path => lib_path("foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "1.0"
- end
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo1, "myrack", "1.0.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
end
- bundle :install, env: { "DEBUG" => "1" }
+ bundle :install, :env => { "DEBUG" => "1" }
expect(out).to match(/re-resolving dependencies/)
expect(lockfile).to eq <<~G
@@ -66,19 +64,19 @@ RSpec.describe Bundler::Definition do
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack (= 1.0)
+ rack (= 1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -91,110 +89,93 @@ RSpec.describe Bundler::Definition do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "ffi"
G
bundle "lock --add-platform java"
- bundle "update ffi", env: { "DEBUG" => "1" }
+ bundle "update ffi", :env => { "DEBUG" => "1" }
expect(out).to match(/because bundler is unlocking gems: \(ffi\)/)
end
it "for a path gem with deps and no changes" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
s.add_development_dependency "net-ssh", "1.0"
end
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo1, "myrack", "1.0.0"
- end
-
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
- expected_lockfile = <<~G
+ bundle :check, :env => { "DEBUG" => "1" }
+
+ expect(out).to match(/using resolution from the lockfile/)
+ expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack (= 1.0)
+ rack (= 1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
-
- expect(lockfile).to eq(expected_lockfile)
-
- bundle :check, env: { "DEBUG" => "1" }
-
- expect(out).to match(/using resolution from the lockfile/)
- expect(lockfile).to eq(expected_lockfile)
end
it "for a locked gem for another platform" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "only_java", platform: :jruby
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "only_java", "1.1", "java"
- end
-
bundle "lock --add-platform java"
- bundle :check, env: { "DEBUG" => "1" }
+ bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
only_java (1.1-java)
PLATFORMS
- #{lockfile_platforms("java")}
+ #{lockfile_platforms_for(["java", specific_local_platform])}
DEPENDENCIES
only_java
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "for a rubygems gem" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "foo", "1.0"
- end
-
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
- bundle :check, env: { "DEBUG" => "1" }
+ bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
foo (1.0)
@@ -203,7 +184,7 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
foo
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -215,13 +196,13 @@ RSpec.describe Bundler::Definition do
context "eager unlock" do
let(:source_list) do
Bundler::SourceList.new.tap do |source_list|
- source_list.add_global_rubygems_remote("https://gem.repo4")
+ source_list.add_global_rubygems_remote(file_uri_for(gem_repo4))
end
end
before do
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'isolated_owner'
gem 'shared_owner_a'
@@ -230,7 +211,7 @@ RSpec.describe Bundler::Definition do
lockfile <<-L
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
isolated_dep (2.0.1)
isolated_owner (1.0.1)
@@ -279,7 +260,7 @@ RSpec.describe Bundler::Definition do
bundled_app_lock,
updated_deps_in_gemfile,
source_list,
- gems: ["shared_owner_a"], conservative: true
+ :gems => ["shared_owner_a"], :conservative => true
)
locked = definition.send(:converge_locked_specs).map(&:name)
expect(locked).to eq %w[isolated_dep isolated_owner shared_dep shared_owner_b]
diff --git a/spec/bundler/bundler/dependency_spec.rb b/spec/bundler/bundler/dependency_spec.rb
index a953372742..9b9e2ddf0a 100644
--- a/spec/bundler/bundler/dependency_spec.rb
+++ b/spec/bundler/bundler/dependency_spec.rb
@@ -40,128 +40,104 @@ RSpec.describe Bundler::Dependency do
# rubocop:disable Naming/VariableNumber
let(:platforms) do
- { ruby: Gem::Platform::RUBY,
- ruby_18: Gem::Platform::RUBY,
- ruby_19: Gem::Platform::RUBY,
- ruby_20: Gem::Platform::RUBY,
- ruby_21: Gem::Platform::RUBY,
- ruby_22: Gem::Platform::RUBY,
- ruby_23: Gem::Platform::RUBY,
- ruby_24: Gem::Platform::RUBY,
- ruby_25: Gem::Platform::RUBY,
- ruby_26: Gem::Platform::RUBY,
- ruby_27: Gem::Platform::RUBY,
- ruby_30: Gem::Platform::RUBY,
- ruby_31: Gem::Platform::RUBY,
- ruby_32: Gem::Platform::RUBY,
- ruby_33: Gem::Platform::RUBY,
- ruby_34: Gem::Platform::RUBY,
- mri: Gem::Platform::RUBY,
- mri_18: Gem::Platform::RUBY,
- mri_19: Gem::Platform::RUBY,
- mri_20: Gem::Platform::RUBY,
- mri_21: Gem::Platform::RUBY,
- mri_22: Gem::Platform::RUBY,
- mri_23: Gem::Platform::RUBY,
- mri_24: Gem::Platform::RUBY,
- mri_25: Gem::Platform::RUBY,
- mri_26: Gem::Platform::RUBY,
- mri_27: Gem::Platform::RUBY,
- mri_30: Gem::Platform::RUBY,
- mri_31: Gem::Platform::RUBY,
- mri_32: Gem::Platform::RUBY,
- mri_33: Gem::Platform::RUBY,
- mri_34: Gem::Platform::RUBY,
- rbx: Gem::Platform::RUBY,
- truffleruby: Gem::Platform::RUBY,
- jruby: Gem::Platform::JAVA,
- jruby_18: Gem::Platform::JAVA,
- jruby_19: Gem::Platform::JAVA,
- windows: Gem::Platform::WINDOWS,
- windows_18: Gem::Platform::WINDOWS,
- windows_19: Gem::Platform::WINDOWS,
- windows_20: Gem::Platform::WINDOWS,
- windows_21: Gem::Platform::WINDOWS,
- windows_22: Gem::Platform::WINDOWS,
- windows_23: Gem::Platform::WINDOWS,
- windows_24: Gem::Platform::WINDOWS,
- windows_25: Gem::Platform::WINDOWS,
- windows_26: Gem::Platform::WINDOWS,
- windows_27: Gem::Platform::WINDOWS,
- windows_30: Gem::Platform::WINDOWS,
- windows_31: Gem::Platform::WINDOWS,
- windows_32: Gem::Platform::WINDOWS,
- windows_33: Gem::Platform::WINDOWS,
- windows_34: Gem::Platform::WINDOWS }
- end
-
- let(:deprecated) do
- { mswin: Gem::Platform::MSWIN,
- mswin_18: Gem::Platform::MSWIN,
- mswin_19: Gem::Platform::MSWIN,
- mswin_20: Gem::Platform::MSWIN,
- mswin_21: Gem::Platform::MSWIN,
- mswin_22: Gem::Platform::MSWIN,
- mswin_23: Gem::Platform::MSWIN,
- mswin_24: Gem::Platform::MSWIN,
- mswin_25: Gem::Platform::MSWIN,
- mswin_26: Gem::Platform::MSWIN,
- mswin_27: Gem::Platform::MSWIN,
- mswin_30: Gem::Platform::MSWIN,
- mswin_31: Gem::Platform::MSWIN,
- mswin_32: Gem::Platform::MSWIN,
- mswin_33: Gem::Platform::MSWIN,
- mswin_34: Gem::Platform::MSWIN,
- mswin64: Gem::Platform::MSWIN64,
- mswin64_19: Gem::Platform::MSWIN64,
- mswin64_20: Gem::Platform::MSWIN64,
- mswin64_21: Gem::Platform::MSWIN64,
- mswin64_22: Gem::Platform::MSWIN64,
- mswin64_23: Gem::Platform::MSWIN64,
- mswin64_24: Gem::Platform::MSWIN64,
- mswin64_25: Gem::Platform::MSWIN64,
- mswin64_26: Gem::Platform::MSWIN64,
- mswin64_27: Gem::Platform::MSWIN64,
- mswin64_30: Gem::Platform::MSWIN64,
- mswin64_31: Gem::Platform::MSWIN64,
- mswin64_32: Gem::Platform::MSWIN64,
- mswin64_33: Gem::Platform::MSWIN64,
- mswin64_34: Gem::Platform::MSWIN64,
- mingw: Gem::Platform::MINGW,
- mingw_18: Gem::Platform::MINGW,
- mingw_19: Gem::Platform::MINGW,
- mingw_20: Gem::Platform::MINGW,
- mingw_21: Gem::Platform::MINGW,
- mingw_22: Gem::Platform::MINGW,
- mingw_23: Gem::Platform::MINGW,
- mingw_24: Gem::Platform::MINGW,
- mingw_25: Gem::Platform::MINGW,
- mingw_26: Gem::Platform::MINGW,
- mingw_27: Gem::Platform::MINGW,
- mingw_30: Gem::Platform::MINGW,
- mingw_31: Gem::Platform::MINGW,
- mingw_32: Gem::Platform::MINGW,
- mingw_33: Gem::Platform::MINGW,
- mingw_34: Gem::Platform::MINGW,
- x64_mingw: Gem::Platform::X64_MINGW,
- x64_mingw_20: Gem::Platform::X64_MINGW,
- x64_mingw_21: Gem::Platform::X64_MINGW,
- x64_mingw_22: Gem::Platform::X64_MINGW,
- x64_mingw_23: Gem::Platform::X64_MINGW,
- x64_mingw_24: Gem::Platform::X64_MINGW,
- x64_mingw_25: Gem::Platform::X64_MINGW,
- x64_mingw_26: Gem::Platform::X64_MINGW,
- x64_mingw_27: Gem::Platform::X64_MINGW,
- x64_mingw_30: Gem::Platform::X64_MINGW,
- x64_mingw_31: Gem::Platform::X64_MINGW,
- x64_mingw_32: Gem::Platform::X64_MINGW,
- x64_mingw_33: Gem::Platform::X64_MINGW,
- x64_mingw_34: Gem::Platform::X64_MINGW }
+ { :ruby => Gem::Platform::RUBY,
+ :ruby_18 => Gem::Platform::RUBY,
+ :ruby_19 => Gem::Platform::RUBY,
+ :ruby_20 => Gem::Platform::RUBY,
+ :ruby_21 => Gem::Platform::RUBY,
+ :ruby_22 => Gem::Platform::RUBY,
+ :ruby_23 => Gem::Platform::RUBY,
+ :ruby_24 => Gem::Platform::RUBY,
+ :ruby_25 => Gem::Platform::RUBY,
+ :ruby_26 => Gem::Platform::RUBY,
+ :ruby_27 => Gem::Platform::RUBY,
+ :ruby_30 => Gem::Platform::RUBY,
+ :ruby_31 => Gem::Platform::RUBY,
+ :mri => Gem::Platform::RUBY,
+ :mri_18 => Gem::Platform::RUBY,
+ :mri_19 => Gem::Platform::RUBY,
+ :mri_20 => Gem::Platform::RUBY,
+ :mri_21 => Gem::Platform::RUBY,
+ :mri_22 => Gem::Platform::RUBY,
+ :mri_23 => Gem::Platform::RUBY,
+ :mri_24 => Gem::Platform::RUBY,
+ :mri_25 => Gem::Platform::RUBY,
+ :mri_26 => Gem::Platform::RUBY,
+ :mri_27 => Gem::Platform::RUBY,
+ :mri_30 => Gem::Platform::RUBY,
+ :mri_31 => Gem::Platform::RUBY,
+ :rbx => Gem::Platform::RUBY,
+ :truffleruby => Gem::Platform::RUBY,
+ :jruby => Gem::Platform::JAVA,
+ :jruby_18 => Gem::Platform::JAVA,
+ :jruby_19 => Gem::Platform::JAVA,
+ :windows => Gem::Platform::WINDOWS,
+ :windows_18 => Gem::Platform::WINDOWS,
+ :windows_19 => Gem::Platform::WINDOWS,
+ :windows_20 => Gem::Platform::WINDOWS,
+ :windows_21 => Gem::Platform::WINDOWS,
+ :windows_22 => Gem::Platform::WINDOWS,
+ :windows_23 => Gem::Platform::WINDOWS,
+ :windows_24 => Gem::Platform::WINDOWS,
+ :windows_25 => Gem::Platform::WINDOWS,
+ :windows_26 => Gem::Platform::WINDOWS,
+ :windows_27 => Gem::Platform::WINDOWS,
+ :windows_30 => Gem::Platform::WINDOWS,
+ :windows_31 => Gem::Platform::WINDOWS,
+ :mswin => Gem::Platform::MSWIN,
+ :mswin_18 => Gem::Platform::MSWIN,
+ :mswin_19 => Gem::Platform::MSWIN,
+ :mswin_20 => Gem::Platform::MSWIN,
+ :mswin_21 => Gem::Platform::MSWIN,
+ :mswin_22 => Gem::Platform::MSWIN,
+ :mswin_23 => Gem::Platform::MSWIN,
+ :mswin_24 => Gem::Platform::MSWIN,
+ :mswin_25 => Gem::Platform::MSWIN,
+ :mswin_26 => Gem::Platform::MSWIN,
+ :mswin_27 => Gem::Platform::MSWIN,
+ :mswin_30 => Gem::Platform::MSWIN,
+ :mswin_31 => Gem::Platform::MSWIN,
+ :mswin64 => Gem::Platform::MSWIN64,
+ :mswin64_19 => Gem::Platform::MSWIN64,
+ :mswin64_20 => Gem::Platform::MSWIN64,
+ :mswin64_21 => Gem::Platform::MSWIN64,
+ :mswin64_22 => Gem::Platform::MSWIN64,
+ :mswin64_23 => Gem::Platform::MSWIN64,
+ :mswin64_24 => Gem::Platform::MSWIN64,
+ :mswin64_25 => Gem::Platform::MSWIN64,
+ :mswin64_26 => Gem::Platform::MSWIN64,
+ :mswin64_27 => Gem::Platform::MSWIN64,
+ :mswin64_30 => Gem::Platform::MSWIN64,
+ :mswin64_31 => Gem::Platform::MSWIN64,
+ :mingw => Gem::Platform::MINGW,
+ :mingw_18 => Gem::Platform::MINGW,
+ :mingw_19 => Gem::Platform::MINGW,
+ :mingw_20 => Gem::Platform::MINGW,
+ :mingw_21 => Gem::Platform::MINGW,
+ :mingw_22 => Gem::Platform::MINGW,
+ :mingw_23 => Gem::Platform::MINGW,
+ :mingw_24 => Gem::Platform::MINGW,
+ :mingw_25 => Gem::Platform::MINGW,
+ :mingw_26 => Gem::Platform::MINGW,
+ :mingw_27 => Gem::Platform::MINGW,
+ :mingw_30 => Gem::Platform::MINGW,
+ :mingw_31 => Gem::Platform::MINGW,
+ :x64_mingw => Gem::Platform::X64_MINGW,
+ :x64_mingw_20 => Gem::Platform::X64_MINGW,
+ :x64_mingw_21 => Gem::Platform::X64_MINGW,
+ :x64_mingw_22 => Gem::Platform::X64_MINGW,
+ :x64_mingw_23 => Gem::Platform::X64_MINGW,
+ :x64_mingw_24 => Gem::Platform::X64_MINGW,
+ :x64_mingw_25 => Gem::Platform::X64_MINGW,
+ :x64_mingw_26 => Gem::Platform::X64_MINGW,
+ :x64_mingw_27 => Gem::Platform::X64_MINGW,
+ :x64_mingw_30 => Gem::Platform::X64_MINGW,
+ :x64_mingw_31 => Gem::Platform::X64_MINGW }
end
# 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 f876827964..841cc0259e 100644
--- a/spec/bundler/bundler/digest_spec.rb
+++ b/spec/bundler/bundler/digest_spec.rb
@@ -1,17 +1,17 @@
# 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"]
- # https://www.rfc-editor.org/rfc/rfc3174#section-7.3
+ # https://datatracker.ietf.org/doc/html/rfc3174#section-7.3
rfc3174_test_cases = ["abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "a", "01234567" * 8]
(random_strings + rfc3174_test_cases).each do |payload|
diff --git a/spec/bundler/bundler/dsl_spec.rb b/spec/bundler/bundler/dsl_spec.rb
index 7b6d080593..8cb51b8a52 100644
--- a/spec/bundler/bundler/dsl_spec.rb
+++ b/spec/bundler/bundler/dsl_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Bundler::Dsl do
it "registers custom hosts" do
subject.git_source(:example) {|repo_name| "git@git.example.com:#{repo_name}.git" }
subject.git_source(:foobar) {|repo_name| "git@foobar.com:#{repo_name}.git" }
- subject.gem("dobry-pies", example: "strzalek/dobry-pies")
+ subject.gem("dobry-pies", :example => "strzalek/dobry-pies")
example_uri = "git@git.example.com:strzalek/dobry-pies.git"
expect(subject.dependencies.first.source.uri).to eq(example_uri)
end
@@ -26,136 +26,85 @@ RSpec.describe Bundler::Dsl do
end
it "converts :github PR to URI using https" do
- subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5")
+ subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5")
github_uri = "https://github.com/indirect/sparks.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
expect(subject.dependencies.first.source.ref).to eq("refs/pull/5/head")
end
- it "converts :gitlab PR to URI using https" do
- subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5")
- gitlab_uri = "https://gitlab.com/indirect/sparks.git"
- expect(subject.dependencies.first.source.uri).to eq(gitlab_uri)
- expect(subject.dependencies.first.source.ref).to eq("refs/merge-requests/5/head")
- end
-
it "rejects :github PR URI with a branch, ref or tag" do
expect do
- subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5", branch: "foo")
+ subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5", :branch => "foo")
end.to raise_error(
Bundler::GemfileError,
%(The :branch option can't be used with `github: "https://github.com/indirect/sparks/pull/5"`),
)
expect do
- subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5", ref: "foo")
+ subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5", :ref => "foo")
end.to raise_error(
Bundler::GemfileError,
%(The :ref option can't be used with `github: "https://github.com/indirect/sparks/pull/5"`),
)
expect do
- subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5", tag: "foo")
+ subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5", :tag => "foo")
end.to raise_error(
Bundler::GemfileError,
%(The :tag option can't be used with `github: "https://github.com/indirect/sparks/pull/5"`),
)
end
- it "rejects :gitlab PR URI with a branch, ref or tag" do
- expect do
- subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5", branch: "foo")
- end.to raise_error(
- Bundler::GemfileError,
- %(The :branch option can't be used with `gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5"`),
- )
-
- expect do
- subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5", ref: "foo")
- end.to raise_error(
- Bundler::GemfileError,
- %(The :ref option can't be used with `gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5"`),
- )
-
- expect do
- subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5", tag: "foo")
- end.to raise_error(
- Bundler::GemfileError,
- %(The :tag option can't be used with `gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5"`),
- )
- end
-
it "rejects :github with :git" do
expect do
- subject.gem("sparks", github: "indirect/sparks", git: "https://github.com/indirect/sparks.git")
+ subject.gem("sparks", :github => "indirect/sparks", :git => "https://github.com/indirect/sparks.git")
end.to raise_error(
Bundler::GemfileError,
%(The :git option can't be used with `github: "indirect/sparks"`),
)
end
- it "rejects :gitlab with :git" do
- expect do
- subject.gem("sparks", gitlab: "indirect/sparks", git: "https://gitlab.com/indirect/sparks.git")
- end.to raise_error(
- Bundler::GemfileError,
- %(The :git option can't be used with `gitlab: "indirect/sparks"`),
- )
- end
-
- context "default hosts", bundler: "< 3" do
+ context "default hosts", :bundler => "< 3" do
it "converts :github to URI using https" do
- subject.gem("sparks", github: "indirect/sparks")
+ subject.gem("sparks", :github => "indirect/sparks")
github_uri = "https://github.com/indirect/sparks.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
it "converts :github shortcut to URI using https" do
- subject.gem("sparks", github: "rails")
+ subject.gem("sparks", :github => "rails")
github_uri = "https://github.com/rails/rails.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
- it "converts :gitlab to URI using https" do
- subject.gem("sparks", gitlab: "indirect/sparks")
- gitlab_uri = "https://gitlab.com/indirect/sparks.git"
- expect(subject.dependencies.first.source.uri).to eq(gitlab_uri)
- end
-
- it "converts :gitlab shortcut to URI using https" do
- subject.gem("sparks", gitlab: "rails")
- gitlab_uri = "https://gitlab.com/rails/rails.git"
- expect(subject.dependencies.first.source.uri).to eq(gitlab_uri)
- end
-
it "converts numeric :gist to :git" do
- subject.gem("not-really-a-gem", gist: 2_859_988)
+ subject.gem("not-really-a-gem", :gist => 2_859_988)
github_uri = "https://gist.github.com/2859988.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
it "converts :gist to :git" do
- subject.gem("not-really-a-gem", gist: "2859988")
+ subject.gem("not-really-a-gem", :gist => "2859988")
github_uri = "https://gist.github.com/2859988.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
it "converts :bitbucket to :git" do
- subject.gem("not-really-a-gem", bitbucket: "mcorp/flatlab-rails")
+ subject.gem("not-really-a-gem", :bitbucket => "mcorp/flatlab-rails")
bitbucket_uri = "https://mcorp@bitbucket.org/mcorp/flatlab-rails.git"
expect(subject.dependencies.first.source.uri).to eq(bitbucket_uri)
end
it "converts 'mcorp' to 'mcorp/mcorp'" do
- subject.gem("not-really-a-gem", bitbucket: "mcorp")
+ subject.gem("not-really-a-gem", :bitbucket => "mcorp")
bitbucket_uri = "https://mcorp@bitbucket.org/mcorp/mcorp.git"
expect(subject.dependencies.first.source.uri).to eq(bitbucket_uri)
end
end
context "default git sources" do
- it "has bitbucket, gist, github, and gitlab" do
- expect(subject.instance_variable_get(:@git_sources).keys.sort).to eq(%w[bitbucket gist github gitlab])
+ it "has bitbucket, gist, and github" do
+ expect(subject.instance_variable_get(:@git_sources).keys.sort).to eq(%w[bitbucket gist github])
end
end
end
@@ -175,7 +124,7 @@ RSpec.describe Bundler::Dsl do
it "handles syntax errors with a useful message" do
expect(Bundler).to receive(:read_file).with(source_root.join("Gemfile").to_s).and_return("}")
expect { subject.eval_gemfile("Gemfile") }.
- to raise_error(Bundler::GemfileError, /There was an error parsing `Gemfile`: (syntax error, unexpected tSTRING_DEND|(compile error - )?syntax error, unexpected '\}'|.+?unexpected '}', ignoring it\n). Bundler cannot continue./m)
+ to raise_error(Bundler::GemfileError, /There was an error parsing `Gemfile`: (syntax error, unexpected tSTRING_DEND|(compile error - )?syntax error, unexpected '\}'). Bundler cannot continue./)
end
it "distinguishes syntax errors from evaluation errors" do
@@ -185,37 +134,21 @@ RSpec.describe Bundler::Dsl do
expect { subject.eval_gemfile("Gemfile") }.
to raise_error(Bundler::GemfileError, /There was an error evaluating `Gemfile`: ruby_version must match the :engine_version for MRI/)
end
-
- it "populates __dir__ and __FILE__ correctly" do
- abs_path = source_root.join("../fragment.rb").to_s
- expect(Bundler).to receive(:read_file).with(abs_path).and_return(<<~RUBY)
- @fragment_dir = __dir__
- @fragment_file = __FILE__
- RUBY
- subject.eval_gemfile("../fragment.rb")
- expect(subject.instance_variable_get(:@fragment_dir)).to eq(source_root.dirname.to_s)
- expect(subject.instance_variable_get(:@fragment_file)).to eq(abs_path)
- end
end
describe "#gem" do
# rubocop:disable Naming/VariableNumber
[:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :ruby_25, :ruby_26, :ruby_27,
- :ruby_30, :ruby_31, :ruby_32, :ruby_33, :mri, :mri_18, :mri_19, :mri_20, :mri_21, :mri_22, :mri_23, :mri_24,
- :mri_25, :mri_26, :mri_27, :mri_30, :mri_31, :mri_32, :mri_33, :jruby, :rbx, :truffleruby].each do |platform|
+ :ruby_30, :ruby_31, :mri, :mri_18, :mri_19, :mri_20, :mri_21, :mri_22, :mri_23, :mri_24, :mri_25, :mri_26,
+ :mri_27, :mri_30, :mri_31, :jruby, :rbx, :truffleruby].each do |platform|
it "allows #{platform} as a valid platform" do
- subject.gem("foo", platform: platform)
+ subject.gem("foo", :platform => platform)
end
end
# rubocop:enable Naming/VariableNumber
- it "allows platforms matching the running Ruby version" do
- platform = "ruby_#{RbConfig::CONFIG["MAJOR"]}#{RbConfig::CONFIG["MINOR"]}"
- subject.gem("foo", platform: platform)
- end
-
it "rejects invalid platforms" do
- expect { subject.gem("foo", platform: :bogus) }.
+ expect { subject.gem("foo", :platform => :bogus) }.
to raise_error(Bundler::GemfileError, /is not a valid platform/)
end
@@ -265,19 +198,19 @@ RSpec.describe Bundler::Dsl do
end
it "rejects branch option on non-git gems" do
- expect { subject.gem("foo", branch: "test") }.
+ expect { subject.gem("foo", :branch => "test") }.
to raise_error(Bundler::GemfileError, /The `branch` option for `gem 'foo'` is not allowed. Only gems with a git source can specify a branch/)
end
it "allows specifying a branch on git gems" do
- subject.gem("foo", branch: "test", git: "http://mytestrepo")
+ subject.gem("foo", :branch => "test", :git => "http://mytestrepo")
dep = subject.dependencies.last
expect(dep.name).to eq "foo"
end
it "allows specifying a branch on git gems with a git_source" do
subject.git_source(:test_source) {|n| "https://github.com/#{n}" }
- subject.gem("foo", branch: "test", test_source: "bundler/bundler")
+ subject.gem("foo", :branch => "test", :test_source => "bundler/bundler")
dep = subject.dependencies.last
expect(dep.name).to eq "foo"
end
@@ -322,7 +255,7 @@ RSpec.describe Bundler::Dsl do
it "will raise a Bundler::GemfileError" do
gemfile "gem 'foo', :path => /unquoted/string/syntax/error"
expect { Bundler::Dsl.evaluate(bundled_app_gemfile, nil, true) }.
- to raise_error(Bundler::GemfileError, /There was an error parsing `Gemfile`:( compile error -)?.+?unknown regexp options - trg.+ Bundler cannot continue./m)
+ to raise_error(Bundler::GemfileError, /There was an error parsing `Gemfile`:( compile error -)? unknown regexp options - trg.+ Bundler cannot continue./)
end
end
@@ -342,7 +275,7 @@ RSpec.describe Bundler::Dsl do
allow(Bundler).to receive(:default_gemfile).and_return(Pathname.new("./Gemfile"))
subject.source("https://other-source.org") do
- subject.gem("dobry-pies", path: "foo")
+ subject.gem("dobry-pies", :path => "foo")
subject.gem("foo")
end
@@ -354,7 +287,7 @@ RSpec.describe Bundler::Dsl do
describe "#check_primary_source_safety" do
context "when a global source is not defined implicitly" do
it "will raise a major deprecation warning" do
- not_a_global_source = double("not-a-global-source", no_remotes?: true)
+ not_a_global_source = double("not-a-global-source", :no_remotes? => true)
allow(Bundler::Source::Rubygems).to receive(:new).and_return(not_a_global_source)
warning = "This Gemfile does not include an explicit global source. " \
diff --git a/spec/bundler/bundler/endpoint_specification_spec.rb b/spec/bundler/bundler/endpoint_specification_spec.rb
index 6518f125ba..7dd6925007 100644
--- a/spec/bundler/bundler/endpoint_specification_spec.rb
+++ b/spec/bundler/bundler/endpoint_specification_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe Bundler::EndpointSpecification do
expect { subject }.to raise_error(
Bundler::GemspecError,
a_string_including("There was an error parsing the metadata for the gem foo (1.0.0)").
- and(a_string_including("The metadata was #{{ "rubygems" => ">\n" }.inspect}"))
+ and(a_string_including('The metadata was {"rubygems"=>">\n"}'))
)
end
end
@@ -60,21 +60,21 @@ RSpec.describe Bundler::EndpointSpecification do
it "should return the remote spec value when not set on endpoint specification and remote spec has one" do
remote_value = "remote_value"
- remote_spec = double(:remote_spec, required_ruby_version: remote_value, required_rubygems_version: nil)
+ remote_spec = double(:remote_spec, :required_ruby_version => remote_value, :required_rubygems_version => nil)
allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
expect(spec.required_ruby_version). eql?(remote_value)
end
it "should use the default Gem Requirement value when not set on endpoint specification and not set on remote spec" do
- remote_spec = double(:remote_spec, required_ruby_version: nil, required_rubygems_version: nil)
+ remote_spec = double(:remote_spec, :required_ruby_version => nil, :required_rubygems_version => nil)
allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
expect(spec.required_ruby_version). eql?(Gem::Requirement.default)
end
end
it "supports equality comparison" do
- remote_spec = double(:remote_spec, required_ruby_version: nil, required_rubygems_version: nil)
+ remote_spec = double(:remote_spec, :required_ruby_version => nil, :required_rubygems_version => nil)
allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
other_spec = described_class.new("bar", version, platform, spec_fetcher, dependencies, metadata)
expect(spec).to eql(spec)
diff --git a/spec/bundler/bundler/env_spec.rb b/spec/bundler/bundler/env_spec.rb
index e0ab0a45e3..186b207b9f 100644
--- a/spec/bundler/bundler/env_spec.rb
+++ b/spec/bundler/bundler/env_spec.rb
@@ -70,16 +70,16 @@ RSpec.describe Bundler::Env do
context "when there is a Gemfile and a lockfile and print_gemfile is true" do
before do
- gemfile "source 'https://gem.repo1'; gem 'myrack', '1.0.0'"
+ gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem 'rack', '1.0.0'"
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
1.10.0
@@ -88,21 +88,21 @@ RSpec.describe Bundler::Env do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
end
- let(:output) { described_class.report(print_gemfile: true) }
+ let(:output) { described_class.report(:print_gemfile => true) }
it "prints the Gemfile" do
expect(output).to include("Gemfile")
- expect(output).to include("'myrack', '1.0.0'")
+ expect(output).to include("'rack', '1.0.0'")
end
it "prints the lockfile" do
expect(output).to include("Gemfile.lock")
- expect(output).to include("myrack (1.0.0)")
+ expect(output).to include("rack (1.0.0)")
end
end
context "when there no Gemfile and print_gemfile is true" do
- let(:output) { described_class.report(print_gemfile: true) }
+ let(:output) { described_class.report(:print_gemfile => true) }
it "prints the environment" do
expect(output).to start_with("## Environment")
@@ -114,7 +114,7 @@ RSpec.describe Bundler::Env do
bundle "config set https://localgemserver.test/ user:pass"
end
- let(:output) { described_class.report(print_gemfile: true) }
+ let(:output) { described_class.report(:print_gemfile => true) }
it "prints the config with redacted values" do
expect(output).to include("https://localgemserver.test")
@@ -128,7 +128,7 @@ RSpec.describe Bundler::Env do
bundle "config set https://localgemserver.test/ api_token:x-oauth-basic"
end
- let(:output) { described_class.report(print_gemfile: true) }
+ let(:output) { described_class.report(:print_gemfile => true) }
it "prints the config with redacted values" do
expect(output).to include("https://localgemserver.test")
@@ -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"
@@ -148,9 +148,9 @@ RSpec.describe Bundler::Env do
end
before do
- gemfile("source 'https://gem.repo1'; gemspec")
+ gemfile("source \"#{file_uri_for(gem_repo1)}\"; gemspec")
- File.open(bundled_app("foo.gemspec"), "wb") do |f|
+ File.open(bundled_app.join("foo.gemspec"), "wb") do |f|
f.write(gemspec)
end
@@ -158,7 +158,7 @@ RSpec.describe Bundler::Env do
end
it "prints the gemspec" do
- output = described_class.report(print_gemspecs: true)
+ output = described_class.report(:print_gemspecs => true)
expect(output).to include("foo.gemspec")
expect(output).to include(gemspec)
@@ -167,18 +167,18 @@ RSpec.describe Bundler::Env do
context "when eval_gemfile is used" do
it "prints all gemfiles" do
- gemfile bundled_app("other/Gemfile-other"), "gem 'myrack'"
- gemfile bundled_app("other/Gemfile"), "eval_gemfile 'Gemfile-other'"
- gemfile bundled_app("Gemfile-alt"), <<-G
- source "https://gem.repo1"
+ create_file bundled_app("other/Gemfile-other"), "gem 'rack'"
+ create_file bundled_app("other/Gemfile"), "eval_gemfile 'Gemfile-other'"
+ create_file bundled_app("Gemfile-alt"), <<-G
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "other/Gemfile"
G
gemfile "eval_gemfile #{bundled_app("Gemfile-alt").to_s.dump}"
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app)
- output = described_class.report(print_gemspecs: true)
- expect(output).to include(<<~ENV)
+ output = described_class.report(:print_gemspecs => true)
+ expect(output).to include(strip_whitespace(<<-ENV))
## Gemfile
### Gemfile
@@ -190,7 +190,7 @@ RSpec.describe Bundler::Env do
### Gemfile-alt
```ruby
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "other/Gemfile"
```
@@ -203,7 +203,7 @@ RSpec.describe Bundler::Env do
### other/Gemfile-other
```ruby
- gem 'myrack'
+ gem 'rack'
```
### Gemfile.lock
@@ -217,7 +217,7 @@ RSpec.describe Bundler::Env do
context "when the git version is OS specific" do
it "includes OS specific information with the version number" do
- expect(git_proxy_stub).to receive(:git_local).with("--version").
+ expect(git_proxy_stub).to receive(:git).with("--version").
and_return("git version 1.2.3 (Apple Git-BS)")
expect(Bundler::Source::Git::GitProxy).to receive(:new).and_return(git_proxy_stub)
diff --git a/spec/bundler/bundler/environment_preserver_spec.rb b/spec/bundler/bundler/environment_preserver_spec.rb
index 6c7066d0c6..530ca6f835 100644
--- a/spec/bundler/bundler/environment_preserver_spec.rb
+++ b/spec/bundler/bundler/environment_preserver_spec.rb
@@ -27,12 +27,8 @@ RSpec.describe Bundler::EnvironmentPreserver do
context "when a key is empty" do
let(:env) { { "foo" => "" } }
- it "should keep the original entry" do
- expect(subject["foo"]).to be_empty
- end
-
- it "should still create backup entries" do
- expect(subject).to have_key "BUNDLER_ORIG_foo"
+ it "should not create backup entries" do
+ expect(subject).not_to have_key "BUNDLER_ORIG_foo"
end
end
@@ -75,12 +71,8 @@ RSpec.describe Bundler::EnvironmentPreserver do
context "when the original key is empty" do
let(:env) { { "foo" => "my-foo", "BUNDLER_ORIG_foo" => "" } }
- it "should restore the original value" do
- expect(subject["foo"]).to be_empty
- end
-
- it "should delete the backup value" do
- expect(subject.key?("BUNDLER_ORIG_foo")).to eq(false)
+ it "should keep the current value" do
+ expect(subject["foo"]).to eq("my-foo")
end
end
end
diff --git a/spec/bundler/bundler/fetcher/base_spec.rb b/spec/bundler/bundler/fetcher/base_spec.rb
index b8c6b57b10..02506591f3 100644
--- a/spec/bundler/bundler/fetcher/base_spec.rb
+++ b/spec/bundler/bundler/fetcher/base_spec.rb
@@ -4,16 +4,15 @@ RSpec.describe Bundler::Fetcher::Base do
let(:downloader) { double(:downloader) }
let(:remote) { double(:remote) }
let(:display_uri) { "http://sample_uri.com" }
- let(:gem_remote_fetcher) { nil }
class TestClass < described_class; end
- subject { TestClass.new(downloader, remote, display_uri, gem_remote_fetcher) }
+ subject { TestClass.new(downloader, remote, display_uri) }
describe "#initialize" do
context "with the abstract Base class" do
it "should raise an error" do
- expect { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }.to raise_error(RuntimeError, "Abstract class")
+ expect { described_class.new(downloader, remote, display_uri) }.to raise_error(RuntimeError, "Abstract class")
end
end
@@ -37,7 +36,7 @@ RSpec.describe Bundler::Fetcher::Base do
end
describe "#fetch_uri" do
- let(:remote_uri_obj) { Gem::URI("http://rubygems.org") }
+ let(:remote_uri_obj) { Bundler::URI("http://rubygems.org") }
before { allow(subject).to receive(:remote_uri).and_return(remote_uri_obj) }
@@ -50,10 +49,10 @@ RSpec.describe Bundler::Fetcher::Base do
end
context "when the remote uri's host is not rubygems.org" do
- let(:remote_uri_obj) { Gem::URI("http://otherhost.org") }
+ let(:remote_uri_obj) { Bundler::URI("http://otherhost.org") }
it "should return the remote uri" do
- expect(subject.fetch_uri).to eq(Gem::URI("http://otherhost.org"))
+ expect(subject.fetch_uri).to eq(Bundler::URI("http://otherhost.org"))
end
end
diff --git a/spec/bundler/bundler/fetcher/compact_index_spec.rb b/spec/bundler/bundler/fetcher/compact_index_spec.rb
index aa536673d9..00eb27edea 100644
--- a/spec/bundler/bundler/fetcher/compact_index_spec.rb
+++ b/spec/bundler/bundler/fetcher/compact_index_spec.rb
@@ -4,18 +4,13 @@
require "bundler/compact_index_client"
RSpec.describe Bundler::Fetcher::CompactIndex do
- let(:response) { double(:response) }
- let(:downloader) { double(:downloader, fetch: response) }
- let(:display_uri) { Gem::URI("http://sampleuri.com") }
- let(:remote) { double(:remote, cache_slug: "lsjdf", uri: display_uri) }
- let(:gem_remote_fetcher) { nil }
- let(:compact_index) { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }
- let(:compact_index_client) { double(:compact_index_client, available?: true, info: [["lskdjf", "1", nil, [], []]]) }
+ let(:downloader) { double(:downloader) }
+ let(:display_uri) { Bundler::URI("http://sampleuri.com") }
+ let(:remote) { double(:remote, :cache_slug => "lsjdf", :uri => display_uri) }
+ let(:compact_index) { described_class.new(downloader, remote, display_uri) }
before do
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified).and_return(true)
allow(compact_index).to receive(:log_specs) {}
- allow(compact_index).to receive(:compact_index_client).and_return(compact_index_client)
end
describe "#specs_for_names" do
@@ -36,6 +31,11 @@ RSpec.describe Bundler::Fetcher::CompactIndex do
end
describe "#available?" do
+ before do
+ allow(compact_index).to receive(:compact_index_client).
+ and_return(double(:compact_index_client, :update_and_parse_checksums! => true))
+ end
+
it "returns true" do
expect(compact_index).to be_available
end
diff --git a/spec/bundler/bundler/fetcher/dependency_spec.rb b/spec/bundler/bundler/fetcher/dependency_spec.rb
index c420b7c07f..7cfc86ef76 100644
--- a/spec/bundler/bundler/fetcher/dependency_spec.rb
+++ b/spec/bundler/bundler/fetcher/dependency_spec.rb
@@ -2,11 +2,10 @@
RSpec.describe Bundler::Fetcher::Dependency do
let(:downloader) { double(:downloader) }
- let(:remote) { double(:remote, uri: Gem::URI("http://localhost:5000")) }
+ let(:remote) { double(:remote, :uri => Bundler::URI("http://localhost:5000")) }
let(:display_uri) { "http://sample_uri.com" }
- let(:gem_remote_fetcher) { nil }
- subject { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }
+ subject { described_class.new(downloader, remote, display_uri) }
describe "#available?" do
let(:dependency_api_uri) { double(:dependency_api_uri) }
@@ -156,9 +155,9 @@ RSpec.describe Bundler::Fetcher::Dependency do
end
end
- shared_examples_for "the error is logged" do
- it "should log the inability to fetch from API at debug level, and mention retrying" do
- expect(Bundler).to receive_message_chain(:ui, :debug).with("could not fetch from the dependency API, trying the full index")
+ shared_examples_for "the error suggests retrying with the full index" do
+ it "should log the inability to fetch from API at debug level" do
+ expect(Bundler).to receive_message_chain(:ui, :debug).with("could not fetch from the dependency API\nit's suggested to retry using the full index via `bundle install --full-index`")
subject.specs(gem_names, full_dependency_list, last_spec_list)
end
end
@@ -167,21 +166,25 @@ RSpec.describe Bundler::Fetcher::Dependency do
before { allow(subject).to receive(:dependency_specs) { raise Bundler::HTTPError.new } }
it_behaves_like "the error is properly handled"
- it_behaves_like "the error is logged"
+ it_behaves_like "the error suggests retrying with the full index"
end
context "when a GemspecError occurs" do
before { allow(subject).to receive(:dependency_specs) { raise Bundler::GemspecError.new } }
it_behaves_like "the error is properly handled"
- it_behaves_like "the error is logged"
+ it_behaves_like "the error suggests retrying with the full index"
end
context "when a MarshalError occurs" do
before { allow(subject).to receive(:dependency_specs) { raise Bundler::MarshalError.new } }
it_behaves_like "the error is properly handled"
- it_behaves_like "the error is logged"
+
+ it "should log the inability to fetch from API and mention retrying" do
+ expect(Bundler).to receive_message_chain(:ui, :debug).with("could not fetch from the dependency API, trying the full index")
+ subject.specs(gem_names, full_dependency_list, last_spec_list)
+ end
end
end
@@ -211,7 +214,7 @@ RSpec.describe Bundler::Fetcher::Dependency do
let(:gem_names) { [%w[foo bar], %w[bundler rubocop]] }
let(:dep_api_uri) { double(:dep_api_uri) }
let(:unmarshalled_gems) { double(:unmarshalled_gems) }
- let(:fetch_response) { double(:fetch_response, body: double(:body)) }
+ let(:fetch_response) { double(:fetch_response, :body => double(:body)) }
let(:rubygems_limit) { 50 }
before { allow(subject).to receive(:dependency_api_uri).with(gem_names).and_return(dep_api_uri) }
@@ -228,20 +231,20 @@ RSpec.describe Bundler::Fetcher::Dependency do
let(:gem_list) do
[
{
- dependencies: {
+ :dependencies => {
"resque" => "req3,req4",
},
- name: "typhoeus",
- number: "1.0.1",
- platform: "ruby",
+ :name => "typhoeus",
+ :number => "1.0.1",
+ :platform => "ruby",
},
{
- dependencies: {
+ :dependencies => {
"faraday" => "req1,req2",
},
- name: "grape",
- number: "2.0.2",
- platform: "jruby",
+ :name => "grape",
+ :number => "2.0.2",
+ :platform => "jruby",
},
]
end
@@ -255,7 +258,7 @@ RSpec.describe Bundler::Fetcher::Dependency do
end
describe "#dependency_api_uri" do
- let(:uri) { Gem::URI("http://gem-api.com") }
+ let(:uri) { Bundler::URI("http://gem-api.com") }
context "with gem names" do
let(:gem_names) { %w[foo bar bundler rubocop] }
diff --git a/spec/bundler/bundler/fetcher/downloader_spec.rb b/spec/bundler/bundler/fetcher/downloader_spec.rb
index d5c32f4730..0412ddb83a 100644
--- a/spec/bundler/bundler/fetcher/downloader_spec.rb
+++ b/spec/bundler/bundler/fetcher/downloader_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe Bundler::Fetcher::Downloader do
let(:connection) { double(:connection) }
let(:redirect_limit) { 5 }
- let(:uri) { Gem::URI("http://www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://www.uri-to-fetch.com/api/v2/endpoint") }
let(:options) { double(:options) }
subject { described_class.new(connection, redirect_limit) }
@@ -27,7 +27,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "logging" do
- let(:http_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
+ let(:http_response) { Net::HTTPSuccess.new("1.1", 200, "Success") }
it "should log the HTTP response code and message to debug" do
expect(Bundler).to receive_message_chain(:ui, :debug).with("HTTP 200 Success #{uri}")
@@ -35,48 +35,48 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
- context "when the request response is a Gem::Net::HTTPRedirection" do
- let(:http_response) { Gem::Net::HTTPRedirection.new(httpv, 308, "Moved") }
+ context "when the request response is a Net::HTTPRedirection" do
+ let(:http_response) { Net::HTTPRedirection.new(httpv, 308, "Moved") }
before { http_response["location"] = "http://www.redirect-uri.com/api/v2/endpoint" }
it "should try to fetch the redirect uri and iterate the # requests counter" do
- expect(subject).to receive(:fetch).with(Gem::URI("http://www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
- expect(subject).to receive(:fetch).with(Gem::URI("http://www.redirect-uri.com/api/v2/endpoint"), options, 1)
+ expect(subject).to receive(:fetch).with(Bundler::URI("http://www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
+ expect(subject).to receive(:fetch).with(Bundler::URI("http://www.redirect-uri.com/api/v2/endpoint"), options, 1)
subject.fetch(uri, options, counter)
end
context "when the redirect uri and original uri are the same" do
- let(:uri) { Gem::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
before { http_response["location"] = "ssh://www.uri-to-fetch.com/api/v1/endpoint" }
it "should set the same user and password for the redirect uri" do
- expect(subject).to receive(:fetch).with(Gem::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
- expect(subject).to receive(:fetch).with(Gem::URI("ssh://username:password@www.uri-to-fetch.com/api/v1/endpoint"), options, 1)
+ expect(subject).to receive(:fetch).with(Bundler::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
+ expect(subject).to receive(:fetch).with(Bundler::URI("ssh://username:password@www.uri-to-fetch.com/api/v1/endpoint"), options, 1)
subject.fetch(uri, options, counter)
end
end
end
- context "when the request response is a Gem::Net::HTTPSuccess" do
- let(:http_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
+ context "when the request response is a Net::HTTPSuccess" do
+ let(:http_response) { Net::HTTPSuccess.new("1.1", 200, "Success") }
it "should return the response body" do
expect(subject.fetch(uri, options, counter)).to eq(http_response)
end
end
- context "when the request response is a Gem::Net::HTTPRequestEntityTooLarge" do
- let(:http_response) { Gem::Net::HTTPRequestEntityTooLarge.new("1.1", 413, "Too Big") }
+ context "when the request response is a Net::HTTPRequestEntityTooLarge" do
+ let(:http_response) { Net::HTTPRequestEntityTooLarge.new("1.1", 413, "Too Big") }
it "should raise a Bundler::Fetcher::FallbackError with the response body" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::FallbackError, "Body with info")
end
end
- context "when the request response is a Gem::Net::HTTPUnauthorized" do
- let(:http_response) { Gem::Net::HTTPUnauthorized.new("1.1", 401, "Unauthorized") }
+ context "when the request response is a Net::HTTPUnauthorized" do
+ let(:http_response) { Net::HTTPUnauthorized.new("1.1", 401, "Unauthorized") }
it "should raise a Bundler::Fetcher::AuthenticationRequiredError with the uri host" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError,
@@ -89,7 +89,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "when the there are credentials provided in the request" do
- let(:uri) { Gem::URI("http://user:password@www.uri-to-fetch.com") }
+ let(:uri) { Bundler::URI("http://user:password@www.uri-to-fetch.com") }
it "should raise a Bundler::Fetcher::BadAuthenticationError that doesn't contain the password" do
expect { subject.fetch(uri, options, counter) }.
@@ -98,39 +98,29 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
- context "when the request response is a Gem::Net::HTTPForbidden" do
- let(:http_response) { Gem::Net::HTTPForbidden.new("1.1", 403, "Forbidden") }
- let(:uri) { Gem::URI("http://user:password@www.uri-to-fetch.com") }
+ context "when the request response is a Net::HTTPNotFound" do
+ let(:http_response) { Net::HTTPNotFound.new("1.1", 404, "Not Found") }
- it "should raise a Bundler::Fetcher::AuthenticationForbiddenError with the uri host" do
- expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::AuthenticationForbiddenError,
- /Access token could not be authenticated for www.uri-to-fetch.com/)
- end
- end
-
- context "when the request response is a Gem::Net::HTTPNotFound" do
- let(:http_response) { Gem::Net::HTTPNotFound.new("1.1", 404, "Not Found") }
-
- it "should raise a Bundler::Fetcher::FallbackError with Gem::Net::HTTPNotFound" do
+ it "should raise a Bundler::Fetcher::FallbackError with Net::HTTPNotFound" do
expect { subject.fetch(uri, options, counter) }.
- to raise_error(Bundler::Fetcher::FallbackError, "Gem::Net::HTTPNotFound: http://www.uri-to-fetch.com/api/v2/endpoint")
+ to raise_error(Bundler::Fetcher::FallbackError, "Net::HTTPNotFound: http://www.uri-to-fetch.com/api/v2/endpoint")
end
context "when the there are credentials provided in the request" do
- let(:uri) { Gem::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
it "should raise a Bundler::Fetcher::FallbackError that doesn't contain the password" do
expect { subject.fetch(uri, options, counter) }.
- to raise_error(Bundler::Fetcher::FallbackError, "Gem::Net::HTTPNotFound: http://username@www.uri-to-fetch.com/api/v2/endpoint")
+ to raise_error(Bundler::Fetcher::FallbackError, "Net::HTTPNotFound: http://username@www.uri-to-fetch.com/api/v2/endpoint")
end
end
end
context "when the request response is some other type" do
- let(:http_response) { Gem::Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") }
+ let(:http_response) { Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") }
it "should raise a Bundler::HTTPError with the response class and body" do
- expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::HTTPError, "Gem::Net::HTTPBadGateway: Body with info")
+ expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::HTTPError, "Net::HTTPBadGateway: Body with info")
end
end
end
@@ -140,7 +130,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
let(:response) { double(:response) }
before do
- allow(Gem::Net::HTTP::Get).to receive(:new).with("/api/v2/endpoint", options).and_return(net_http_get)
+ allow(Net::HTTP::Get).to receive(:new).with("/api/v2/endpoint", options).and_return(net_http_get)
allow(connection).to receive(:request).with(uri, net_http_get).and_return(response)
end
@@ -152,7 +142,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
context "when there is a user provided in the request" do
context "and there is also a password provided" do
context "that contains cgi escaped characters" do
- let(:uri) { Gem::URI("http://username:password%24@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username:password%24@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with the username and password" do
expect(net_http_get).to receive(:basic_auth).with("username", "password$")
@@ -161,7 +151,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "that is all unescaped characters" do
- let(:uri) { Gem::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with the username and proper cgi compliant password" do
expect(net_http_get).to receive(:basic_auth).with("username", "password")
subject.request(uri, options)
@@ -170,7 +160,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "and there is no password provided" do
- let(:uri) { Gem::URI("http://username@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with just the user" do
expect(net_http_get).to receive(:basic_auth).with("username", nil)
@@ -179,7 +169,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "that contains cgi escaped characters" do
- let(:uri) { Gem::URI("http://username%24@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username%24@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with the proper cgi compliant password user" do
expect(net_http_get).to receive(:basic_auth).with("username$", nil)
@@ -230,7 +220,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "when the there are credentials provided in the request" do
- let(:uri) { Gem::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
before do
allow(net_http_get).to receive(:basic_auth).with("username", "password")
end
diff --git a/spec/bundler/bundler/fetcher/index_spec.rb b/spec/bundler/bundler/fetcher/index_spec.rb
index dff9ccc3cc..f0db07583c 100644
--- a/spec/bundler/bundler/fetcher/index_spec.rb
+++ b/spec/bundler/bundler/fetcher/index_spec.rb
@@ -8,9 +8,8 @@ RSpec.describe Bundler::Fetcher::Index do
let(:display_uri) { "http://sample_uri.com" }
let(:rubygems) { double(:rubygems) }
let(:gem_names) { %w[foo bar] }
- let(:gem_remote_fetcher) { nil }
- subject { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }
+ subject { described_class.new(downloader, remote, display_uri) }
before { allow(Bundler).to receive(:rubygems).and_return(rubygems) }
@@ -20,7 +19,7 @@ RSpec.describe Bundler::Fetcher::Index do
end
context "error handling" do
- let(:remote_uri) { Gem::URI("http://remote-uri.org") }
+ let(:remote_uri) { Bundler::URI("http://remote-uri.org") }
before do
allow(rubygems).to receive(:fetch_all_remote_specs) { raise Gem::RemoteFetcher::FetchError.new(error_message, display_uri) }
allow(subject).to receive(:remote_uri).and_return(remote_uri)
@@ -64,16 +63,33 @@ RSpec.describe Bundler::Fetcher::Index do
context "when a 403 response occurs" do
let(:error_message) { "403" }
- it "should raise a Bundler::Fetcher::AuthenticationForbiddenError" do
- expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::AuthenticationForbiddenError,
- %r{Access token could not be authenticated for http://remote-uri.org})
+ before do
+ allow(remote_uri).to receive(:userinfo).and_return(userinfo)
+ end
+
+ context "and there was userinfo" do
+ let(:userinfo) { double(:userinfo) }
+
+ it "should raise a Bundler::Fetcher::BadAuthenticationError" do
+ expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::BadAuthenticationError,
+ %r{Bad username or password for http://remote-uri.org})
+ end
+ end
+
+ context "and there was no userinfo" do
+ let(:userinfo) { nil }
+
+ it "should raise a Bundler::Fetcher::AuthenticationRequiredError" do
+ expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError,
+ %r{Authentication is required for http://remote-uri.org})
+ end
end
end
context "any other message is returned" do
let(:error_message) { "You get an error, you get an error!" }
- before { allow(Bundler).to receive(:ui).and_return(double(trace: nil)) }
+ before { allow(Bundler).to receive(:ui).and_return(double(:trace => nil)) }
it "should raise a Bundler::HTTPError" do
expect { subject.specs(gem_names) }.to raise_error(Bundler::HTTPError, "Could not fetch specs from http://sample_uri.com due to underlying error <You get an error, you get an error! (http://sample_uri.com)>")
diff --git a/spec/bundler/bundler/fetcher_spec.rb b/spec/bundler/bundler/fetcher_spec.rb
index e20f7e7c48..a104760075 100644
--- a/spec/bundler/bundler/fetcher_spec.rb
+++ b/spec/bundler/bundler/fetcher_spec.rb
@@ -3,8 +3,8 @@
require "bundler/fetcher"
RSpec.describe Bundler::Fetcher do
- let(:uri) { Gem::URI("https://example.com") }
- let(:remote) { double("remote", uri: uri, original_uri: nil) }
+ let(:uri) { Bundler::URI("https://example.com") }
+ let(:remote) { double("remote", :uri => uri, :original_uri => nil) }
subject(:fetcher) { Bundler::Fetcher.new(remote) }
@@ -45,9 +45,9 @@ RSpec.describe Bundler::Fetcher do
end
context "when a rubygems source mirror is set" do
- let(:orig_uri) { Gem::URI("http://zombo.com") }
+ let(:orig_uri) { Bundler::URI("http://zombo.com") }
let(:remote_with_mirror) do
- double("remote", uri: uri, original_uri: orig_uri, anonymized_uri: uri)
+ double("remote", :uri => uri, :original_uri => orig_uri, :anonymized_uri => uri)
end
let(:fetcher) { Bundler::Fetcher.new(remote_with_mirror) }
@@ -61,7 +61,7 @@ RSpec.describe Bundler::Fetcher do
context "when there is no rubygems source mirror set" do
let(:remote_no_mirror) do
- double("remote", uri: uri, original_uri: nil, anonymized_uri: uri)
+ double("remote", :uri => uri, :original_uri => nil, :anonymized_uri => uri)
end
let(:fetcher) { Bundler::Fetcher.new(remote_no_mirror) }
@@ -114,9 +114,9 @@ RSpec.describe Bundler::Fetcher do
context "when gem ssl configuration is set" do
before do
allow(Gem.configuration).to receive_messages(
- http_proxy: nil,
- ssl_client_cert: "cert",
- ssl_ca_cert: "ca"
+ :http_proxy => nil,
+ :ssl_client_cert => "cert",
+ :ssl_ca_cert => "ca"
)
expect(File).to receive(:read).and_return("")
expect(OpenSSL::X509::Certificate).to receive(:new).and_return("cert")
@@ -143,118 +143,20 @@ RSpec.describe Bundler::Fetcher do
describe "include CI information" do
it "from one CI" do
- with_env_vars("CI" => nil, "JENKINS_URL" => "foo") do
+ with_env_vars("JENKINS_URL" => "foo") do
ci_part = fetcher.user_agent.split(" ").find {|x| x.start_with?("ci/") }
- cis = ci_part.split("/").last.split(",")
- expect(cis).to include("jenkins")
- expect(cis).not_to include("ci")
+ expect(ci_part).to match("jenkins")
end
end
it "from many CI" do
- with_env_vars("CI" => "true", "SEMAPHORE" => nil, "TRAVIS" => "foo", "GITLAB_CI" => "gitlab", "CI_NAME" => "MY_ci") do
+ with_env_vars("TRAVIS" => "foo", "GITLAB_CI" => "gitlab", "CI_NAME" => "my_ci") do
ci_part = fetcher.user_agent.split(" ").find {|x| x.start_with?("ci/") }
- cis = ci_part.split("/").last.split(",")
- expect(cis).to include("ci", "gitlab", "my_ci", "travis")
- expect(cis).not_to include("semaphore")
+ expect(ci_part).to match("travis")
+ expect(ci_part).to match("gitlab")
+ expect(ci_part).to match("my_ci")
end
end
end
end
-
- describe "#fetch_spec" do
- let(:name) { "name" }
- let(:version) { "1.3.17" }
- let(:platform) { "platform" }
- let(:downloader) { double("downloader") }
- let(:body) { double(Gem::Net::HTTP::Get, body: downloaded_data) }
-
- context "when attempting to load a Gem::Specification" do
- let(:spec) { Gem::Specification.new(name, version) }
- let(:downloaded_data) { Zlib::Deflate.deflate(Marshal.dump(spec)) }
-
- it "returns the spec" do
- expect(Bundler::Fetcher::Downloader).to receive(:new).and_return(downloader)
- expect(downloader).to receive(:fetch).once.and_return(body)
- result = fetcher.fetch_spec([name, version, platform])
- expect(result).to eq(spec)
- end
- end
-
- context "when attempting to load an unexpected class" do
- let(:downloaded_data) { Zlib::Deflate.deflate(Marshal.dump(3)) }
-
- it "raises a HTTPError error" do
- expect(Bundler::Fetcher::Downloader).to receive(:new).and_return(downloader)
- expect(downloader).to receive(:fetch).once.and_return(body)
- expect { fetcher.fetch_spec([name, version, platform]) }.to raise_error(Bundler::HTTPError, /Gemspec .* contained invalid data/i)
- 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/friendly_errors_spec.rb b/spec/bundler/bundler/friendly_errors_spec.rb
index 255019f40a..37afe488f3 100644
--- a/spec/bundler/bundler/friendly_errors_spec.rb
+++ b/spec/bundler/bundler/friendly_errors_spec.rb
@@ -18,11 +18,11 @@ RSpec.describe Bundler, "friendly errors" do
it "reports a relevant friendly error message" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle :install, env: { "DEBUG" => "true" }
+ bundle :install, :env => { "DEBUG" => "true" }
expect(err).to include("Failed to load #{home(".gemrc")}")
end
@@ -101,7 +101,7 @@ RSpec.describe Bundler, "friendly errors" do
context "BundlerError" do
it "Bundler.ui receive error" do
error = Bundler::BundlerError.new
- expect(Bundler.ui).to receive(:error).with(error.message, wrap: true)
+ expect(Bundler.ui).to receive(:error).with(error.message, :wrap => true)
Bundler::FriendlyErrors.log_error(error)
end
end
@@ -121,7 +121,7 @@ RSpec.describe Bundler, "friendly errors" do
context "Gem::InvalidSpecificationException" do
it "Bundler.ui receive error" do
error = Gem::InvalidSpecificationException.new
- expect(Bundler.ui).to receive(:error).with(error.message, wrap: true)
+ expect(Bundler.ui).to receive(:error).with(error.message, :wrap => true)
Bundler::FriendlyErrors.log_error(error)
end
end
diff --git a/spec/bundler/bundler/gem_helper_spec.rb b/spec/bundler/bundler/gem_helper_spec.rb
index 94f66537d3..7d955007ab 100644
--- a/spec/bundler/bundler/gem_helper_spec.rb
+++ b/spec/bundler/bundler/gem_helper_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Bundler::GemHelper do
before(:each) do
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false",
"BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
- git("config --global init.defaultBranch main")
+ sys_exec("git config --global init.defaultBranch main")
bundle "gem #{app_name}"
prepare_gemspec(app_gemspec_path)
end
@@ -253,11 +253,11 @@ RSpec.describe Bundler::GemHelper do
end
before do
- git("init", app_path)
- git("config user.email \"you@example.com\"", app_path)
- git("config user.name \"name\"", app_path)
- git("config commit.gpgsign false", app_path)
- git("config push.default simple", app_path)
+ sys_exec("git init", :dir => app_path)
+ sys_exec("git config user.email \"you@example.com\"", :dir => app_path)
+ sys_exec("git config user.name \"name\"", :dir => app_path)
+ sys_exec("git config commit.gpgsign false", :dir => app_path)
+ sys_exec("git config push.default simple", :dir => app_path)
# silence messages
allow(Bundler.ui).to receive(:confirm)
@@ -271,23 +271,23 @@ RSpec.describe Bundler::GemHelper do
end
it "when there are uncommitted files" do
- git("add .", app_path)
+ sys_exec("git add .", :dir => app_path)
expect { Rake.application["release"].invoke }.
to raise_error("There are files that need to be committed first.")
end
it "when there is no git remote" do
- git("commit -a -m \"initial commit\"", app_path)
+ sys_exec("git commit -a -m \"initial commit\"", :dir => app_path)
expect { Rake.application["release"].invoke }.to raise_error(RuntimeError)
end
end
context "succeeds" do
- let(:repo) { build_git("foo", bare: true) }
+ let(:repo) { build_git("foo", :bare => true) }
before do
- git("remote add origin #{repo.path}", app_path)
- git('commit -a -m "initial commit"', app_path)
+ sys_exec("git remote add origin #{file_uri_for(repo.path)}", :dir => app_path)
+ sys_exec('git commit -a -m "initial commit"', :dir => app_path)
end
context "on releasing" do
@@ -296,7 +296,7 @@ RSpec.describe Bundler::GemHelper do
mock_confirm_message "Tagged v#{app_version}."
mock_confirm_message "Pushed git commits and release tag."
- git("push -u origin main", app_path)
+ sys_exec("git push -u origin main", :dir => app_path)
end
it "calls rubygem_push with proper arguments" do
@@ -314,8 +314,8 @@ RSpec.describe Bundler::GemHelper do
it "also works when releasing from an ambiguous reference" do
# Create a branch with the same name as the tag
- git("checkout -b v#{app_version}", app_path)
- git("push -u origin v#{app_version}", app_path)
+ sys_exec("git checkout -b v#{app_version}", :dir => app_path)
+ sys_exec("git push -u origin v#{app_version}", :dir => app_path)
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
@@ -323,7 +323,7 @@ RSpec.describe Bundler::GemHelper do
end
it "also works with releasing from a branch not yet pushed" do
- git("checkout -b module_function", app_path)
+ sys_exec("git checkout -b module_function", :dir => app_path)
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
@@ -337,7 +337,7 @@ RSpec.describe Bundler::GemHelper do
mock_build_message app_name, app_version
mock_confirm_message "Pushed git commits and release tag."
- git("push -u origin main", app_path)
+ sys_exec("git push -u origin main", :dir => app_path)
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
end
@@ -353,7 +353,7 @@ RSpec.describe Bundler::GemHelper do
mock_confirm_message "Tag v#{app_version} has already been created."
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
- git("tag -a -m \"Version #{app_version}\" v#{app_version}", app_path)
+ sys_exec("git tag -a -m \"Version #{app_version}\" v#{app_version}", :dir => app_path)
Rake.application["release"].invoke
end
@@ -374,10 +374,10 @@ RSpec.describe Bundler::GemHelper do
end
before do
- git("init", app_path)
- git("config user.email \"you@example.com\"", app_path)
- git("config user.name \"name\"", app_path)
- git("config push.gpgsign simple", app_path)
+ sys_exec("git init", :dir => app_path)
+ sys_exec("git config user.email \"you@example.com\"", :dir => app_path)
+ sys_exec("git config user.name \"name\"", :dir => app_path)
+ sys_exec("git config push.gpgsign simple", :dir => app_path)
# silence messages
allow(Bundler.ui).to receive(:confirm)
diff --git a/spec/bundler/bundler/gem_version_promoter_spec.rb b/spec/bundler/bundler/gem_version_promoter_spec.rb
index 917daba95d..b5c0f69795 100644
--- a/spec/bundler/bundler/gem_version_promoter_spec.rb
+++ b/spec/bundler/bundler/gem_version_promoter_spec.rb
@@ -1,162 +1,175 @@
# frozen_string_literal: true
RSpec.describe Bundler::GemVersionPromoter do
- let(:gvp) { described_class.new }
-
- # Rightmost (highest array index) in result is most preferred.
- # Leftmost (lowest array index) in result is least preferred.
- # `build_candidates` has all versions of gem in index.
- # `build_spec` is the version currently in the .lock file.
- #
- # In default (not strict) mode, all versions in the index will
- # be returned, allowing Bundler the best chance to resolve all
- # dependencies, but sometimes resulting in upgrades that some
- # would not consider conservative.
-
- describe "#sort_versions" do
+ context "conservative resolver" do
+ def versions(result)
+ result.flatten.map(&:version).map(&:to_s)
+ end
+
def build_candidates(versions)
versions.map do |v|
Bundler::Resolver::Candidate.new(v)
end
end
- def build_package(name, version, locked = [])
- Bundler::Resolver::Package.new(name, [], locked_specs: Bundler::SpecSet.new(build_spec(name, version)), unlock: locked)
+ def build_spec_set(name, v)
+ Bundler::SpecSet.new(build_spec(name, v))
end
- def sorted_versions(candidates:, current:, name: "foo", locked: [])
- gvp.sort_versions(
- build_package(name, current, locked),
- build_candidates(candidates)
- ).flatten.map(&:version).map(&:to_s)
+ def build_package(name, platforms, locked_specs, unlock)
+ Bundler::Resolver::Package.new(name, platforms, :locked_specs => locked_specs, :unlock => unlock)
end
- it "numerically sorts versions" do
- versions = sorted_versions(candidates: %w[1.7.7 1.7.8 1.7.9 1.7.15 1.8.0], current: "1.7.8")
- expect(versions).to eq %w[1.8.0 1.7.15 1.7.9 1.7.8 1.7.7]
- end
-
- context "with no options" do
- it "defaults to level=:major, strict=false, pre=false" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[2.1.0 2.0.1 1.0.0 0.9.0 0.3.1 0.3.0 0.2.0]
- end
- end
-
- context "when strict" do
- before { gvp.strict = true }
-
- context "when level is major" do
- before { gvp.level = :major }
-
- it "keeps downgrades" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[2.1.0 2.0.1 1.0.0 0.9.0 0.3.1 0.3.0 0.2.0]
+ # Rightmost (highest array index) in result is most preferred.
+ # Leftmost (lowest array index) in result is least preferred.
+ # `build_candidates` has all versions of gem in index.
+ # `build_spec` is the version currently in the .lock file.
+ #
+ # In default (not strict) mode, all versions in the index will
+ # be returned, allowing Bundler the best chance to resolve all
+ # dependencies, but sometimes resulting in upgrades that some
+ # would not consider conservative.
+ context "filter specs (strict) level patch" do
+ let(:gvp) do
+ Bundler::GemVersionPromoter.new.tap do |gvp|
+ gvp.level = :patch
+ gvp.strict = true
end
end
- context "when level is minor" do
- before { gvp.level = :minor }
-
- it "sorts highest minor within same major in first position" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[0.9.0 0.3.1 0.3.0 1.0.0 2.1.0 2.0.1 0.2.0]
- end
+ it "when keeping build_spec, keep current, next release" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "1.7.8"), []),
+ build_candidates(%w[1.7.8 1.7.9 1.8.0])
+ )
+ expect(versions(res)).to eq %w[1.7.8 1.7.9]
end
- context "when level is patch" do
- before { gvp.level = :patch }
+ it "when unlocking prefer next release first" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "1.7.8"), []),
+ build_candidates(%w[1.7.8 1.7.9 1.8.0])
+ )
+ expect(versions(res)).to eq %w[1.7.8 1.7.9]
+ end
- it "sorts highest patch within same minor in first position" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[0.3.1 0.3.0 0.9.0 1.0.0 2.0.1 2.1.0 0.2.0]
- end
+ it "when unlocking keep current when already at latest release" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "1.7.9"), []),
+ build_candidates(%w[1.7.9 1.8.0 2.0.0])
+ )
+ expect(versions(res)).to eq %w[1.7.9]
end
end
- context "when not strict" do
- before { gvp.strict = false }
-
- context "when level is major" do
- before { gvp.level = :major }
-
- it "orders by version" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[2.1.0 2.0.1 1.0.0 0.9.0 0.3.1 0.3.0 0.2.0]
+ context "filter specs (strict) level minor" do
+ let(:gvp) do
+ Bundler::GemVersionPromoter.new.tap do |gvp|
+ gvp.level = :minor
+ gvp.strict = true
end
end
- context "when level is minor" do
- before { gvp.level = :minor }
-
- it "favors minor upgrades, then patch upgrades, then major upgrades, then downgrades" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[0.9.0 0.3.1 0.3.0 1.0.0 2.1.0 2.0.1 0.2.0]
- end
+ it "when unlocking favor next releases, remove minor and major increases" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "0.2.0"), []),
+ build_candidates(%w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1])
+ )
+ expect(versions(res)).to eq %w[0.2.0 0.3.0 0.3.1 0.9.0]
end
- context "when level is patch" do
- before { gvp.level = :patch }
+ it "when keep locked, keep current, then favor next release, remove minor and major increases" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "0.2.0"), ["bar"]),
+ build_candidates(%w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1])
+ )
+ expect(versions(res)).to eq %w[0.3.0 0.3.1 0.9.0 0.2.0]
+ end
+ end
- it "favors patch upgrades, then minor upgrades, then major upgrades, then downgrades" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[0.3.1 0.3.0 0.9.0 1.0.0 2.0.1 2.1.0 0.2.0]
+ context "sort specs (not strict) level patch" do
+ let(:gvp) do
+ Bundler::GemVersionPromoter.new.tap do |gvp|
+ gvp.level = :patch
+ gvp.strict = false
end
end
- end
- context "when pre" do
- before { gvp.pre = true }
+ it "when not unlocking, same order but make sure build_spec version is most preferred to stay put" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "1.7.7"), ["bar"]),
+ build_candidates(%w[1.5.4 1.6.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 2.0.0 2.0.1])
+ )
+ expect(versions(res)).to eq %w[1.5.4 1.6.5 1.7.6 2.0.0 2.0.1 1.8.0 1.8.1 1.7.8 1.7.9 1.7.7]
+ end
- it "sorts regardless of prerelease status" do
- versions = sorted_versions(candidates: %w[1.7.7.pre 1.8.0 1.8.1.pre 1.8.1 2.0.0.pre 2.0.0], current: "1.8.0")
- expect(versions).to eq %w[2.0.0 2.0.0.pre 1.8.1 1.8.1.pre 1.8.0 1.7.7.pre]
+ it "when unlocking favor next release, then current over minor increase" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "1.7.8"), []),
+ build_candidates(%w[1.7.7 1.7.8 1.7.9 1.8.0])
+ )
+ expect(versions(res)).to eq %w[1.7.7 1.8.0 1.7.8 1.7.9]
end
- end
- context "when not pre" do
- before { gvp.pre = false }
+ it "when unlocking do proper integer comparison, not string" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "1.7.8"), []),
+ build_candidates(%w[1.7.7 1.7.8 1.7.9 1.7.15 1.8.0])
+ )
+ expect(versions(res)).to eq %w[1.7.7 1.8.0 1.7.8 1.7.9 1.7.15]
+ end
- it "deprioritizes prerelease gems" do
- versions = sorted_versions(candidates: %w[1.7.7.pre 1.8.0 1.8.1.pre 1.8.1 2.0.0.pre 2.0.0], current: "1.8.0")
- expect(versions).to eq %w[2.0.0 1.8.1 1.8.0 2.0.0.pre 1.8.1.pre 1.7.7.pre]
+ it "leave current when unlocking but already at latest release" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "1.7.9"), []),
+ build_candidates(%w[1.7.9 1.8.0 2.0.0])
+ )
+ expect(versions(res)).to eq %w[2.0.0 1.8.0 1.7.9]
end
end
- context "when locking and not major" do
- before { gvp.level = :minor }
+ context "sort specs (not strict) level minor" do
+ let(:gvp) do
+ Bundler::GemVersionPromoter.new.tap do |gvp|
+ gvp.level = :minor
+ gvp.strict = false
+ end
+ end
- it "keeps the current version first" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.1.0 2.0.1], current: "0.3.0", locked: ["bar"])
- expect(versions.first).to eq("0.3.0")
+ it "when unlocking favor next release, then minor increase over current" do
+ res = gvp.sort_versions(
+ build_package("foo", [], build_spec_set("foo", "0.2.0"), []),
+ build_candidates(%w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.0 2.0.1])
+ )
+ expect(versions(res)).to eq %w[2.0.0 2.0.1 1.0.0 0.2.0 0.3.0 0.3.1 0.9.0]
end
end
- end
- describe "#level=" do
- subject { described_class.new }
+ context "level error handling" do
+ subject { Bundler::GemVersionPromoter.new }
- it "should raise if not major, minor or patch is passed" do
- expect { subject.level = :minjor }.to raise_error ArgumentError
- end
+ it "should raise if not major, minor or patch is passed" do
+ expect { subject.level = :minjor }.to raise_error ArgumentError
+ end
- it "should raise if invalid classes passed" do
- [123, nil].each do |value|
- expect { subject.level = value }.to raise_error ArgumentError
+ it "should raise if invalid classes passed" do
+ [123, nil].each do |value|
+ expect { subject.level = value }.to raise_error ArgumentError
+ end
end
- end
- it "should accept major, minor patch symbols" do
- [:major, :minor, :patch].each do |value|
- subject.level = value
- expect(subject.level).to eq value
+ it "should accept major, minor patch symbols" do
+ [:major, :minor, :patch].each do |value|
+ subject.level = value
+ expect(subject.level).to eq value
+ end
end
- end
- it "should accept major, minor patch strings" do
- %w[major minor patch].each do |value|
- subject.level = value
- expect(subject.level).to eq value.to_sym
+ it "should accept major, minor patch strings" do
+ %w[major minor patch].each do |value|
+ subject.level = value
+ expect(subject.level).to eq value.to_sym
+ end
end
end
end
diff --git a/spec/bundler/bundler/installer/gem_installer_spec.rb b/spec/bundler/bundler/installer/gem_installer_spec.rb
index 6583bd8181..e86bdf009a 100644
--- a/spec/bundler/bundler/installer/gem_installer_spec.rb
+++ b/spec/bundler/bundler/installer/gem_installer_spec.rb
@@ -3,11 +3,10 @@
require "bundler/installer/gem_installer"
RSpec.describe Bundler::GemInstaller do
- let(:definition) { instance_double("Definition", locked_gems: nil) }
- let(:installer) { instance_double("Installer", definition: definition) }
+ let(:definition) { instance_double("Definition", :locked_gems => nil) }
+ let(:installer) { instance_double("Installer", :definition => definition) }
let(:spec_source) { instance_double("SpecSource") }
- let(:spec) { instance_double("Specification", name: "dummy", version: "0.0.1", loaded_from: "dummy", source: spec_source) }
- let(:base_options) { { force: false, local: false, previous_spec: nil } }
+ let(:spec) { instance_double("Specification", :name => "dummy", :version => "0.0.1", :loaded_from => "dummy", :source => spec_source) }
subject { described_class.new(spec, installer) }
@@ -15,7 +14,7 @@ RSpec.describe Bundler::GemInstaller do
it "invokes install method with empty build_args" do
allow(spec_source).to receive(:install).with(
spec,
- base_options.merge(build_args: [])
+ { :force => false, :ensure_builtin_gems_cached => false, :build_args => [], :previous_spec => nil }
)
subject.install_from_spec
end
@@ -29,7 +28,7 @@ RSpec.describe Bundler::GemInstaller do
allow(Bundler.settings).to receive(:[]).with("build.dummy").and_return("--with-dummy-config=dummy")
expect(spec_source).to receive(:install).with(
spec,
- base_options.merge(build_args: ["--with-dummy-config=dummy"])
+ { :force => false, :ensure_builtin_gems_cached => false, :build_args => ["--with-dummy-config=dummy"], :previous_spec => nil }
)
subject.install_from_spec
end
@@ -43,7 +42,7 @@ RSpec.describe Bundler::GemInstaller do
allow(Bundler.settings).to receive(:[]).with("build.dummy").and_return("--with-dummy-config=dummy --with-another-dummy-config")
expect(spec_source).to receive(:install).with(
spec,
- base_options.merge(build_args: ["--with-dummy-config=dummy", "--with-another-dummy-config"])
+ { :force => false, :ensure_builtin_gems_cached => false, :build_args => ["--with-dummy-config=dummy", "--with-another-dummy-config"], :previous_spec => nil }
)
subject.install_from_spec
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..f67d03356d
--- /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 trying to manually editing the bad locked gems to a version that satisfies all dependencies.
+The unmet dependencies are:
+* diff-lcs (< 1.4), depended upon 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/installer/spec_installation_spec.rb b/spec/bundler/bundler/installer/spec_installation_spec.rb
index cbe2589b99..e63ef26cb3 100644
--- a/spec/bundler/bundler/installer/spec_installation_spec.rb
+++ b/spec/bundler/bundler/installer/spec_installation_spec.rb
@@ -42,26 +42,24 @@ RSpec.describe Bundler::ParallelInstaller::SpecInstallation do
context "when all dependencies are installed" do
it "returns true" do
dependencies = []
- dependencies << instance_double("SpecInstallation", spec: "alpha", name: "alpha", installed?: true, all_dependencies: [], type: :production)
- dependencies << instance_double("SpecInstallation", spec: "beta", name: "beta", installed?: true, all_dependencies: [], type: :production)
- all_specs = dependencies + [instance_double("SpecInstallation", spec: "gamma", name: "gamma", installed?: false, all_dependencies: [], type: :production)]
+ dependencies << instance_double("SpecInstallation", :spec => "alpha", :name => "alpha", :installed? => true, :all_dependencies => [], :type => :production)
+ dependencies << instance_double("SpecInstallation", :spec => "beta", :name => "beta", :installed? => true, :all_dependencies => [], :type => :production)
+ all_specs = dependencies + [instance_double("SpecInstallation", :spec => "gamma", :name => "gamma", :installed? => false, :all_dependencies => [], :type => :production)]
spec = described_class.new(dep)
allow(spec).to receive(:all_dependencies).and_return(dependencies)
- installed_specs = all_specs.select(&:installed?).map {|s| [s.name, true] }.to_h
- expect(spec.dependencies_installed?(installed_specs)).to be_truthy
+ expect(spec.dependencies_installed?(all_specs)).to be_truthy
end
end
context "when all dependencies are not installed" do
it "returns false" do
dependencies = []
- dependencies << instance_double("SpecInstallation", spec: "alpha", name: "alpha", installed?: false, all_dependencies: [], type: :production)
- dependencies << instance_double("SpecInstallation", spec: "beta", name: "beta", installed?: true, all_dependencies: [], type: :production)
- all_specs = dependencies + [instance_double("SpecInstallation", spec: "gamma", name: "gamma", installed?: false, all_dependencies: [], type: :production)]
+ dependencies << instance_double("SpecInstallation", :spec => "alpha", :name => "alpha", :installed? => false, :all_dependencies => [], :type => :production)
+ dependencies << instance_double("SpecInstallation", :spec => "beta", :name => "beta", :installed? => true, :all_dependencies => [], :type => :production)
+ all_specs = dependencies + [instance_double("SpecInstallation", :spec => "gamma", :name => "gamma", :installed? => false, :all_dependencies => [], :type => :production)]
spec = described_class.new(dep)
allow(spec).to receive(:all_dependencies).and_return(dependencies)
- installed_specs = all_specs.select(&:installed?).map {|s| [s.name, true] }.to_h
- expect(spec.dependencies_installed?(installed_specs)).to be_falsey
+ expect(spec.dependencies_installed?(all_specs)).to be_falsey
end
end
end
diff --git a/spec/bundler/bundler/lockfile_parser_spec.rb b/spec/bundler/bundler/lockfile_parser_spec.rb
index 88932bf009..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,14 +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_sha256_checksum) do
- Bundler::Checksum.from_lock(
- "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
- "#{lockfile_path}:20:17"
- )
- end
- let(:rake_checksums) { [rake_sha256_checksum] }
shared_examples_for "parsing" do
it "parses correctly" do
@@ -136,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
- rake_spec = specs.last
- checksums = subject.sources.last.checksum_store.to_lock(specs.last)
- expect(checksums).to eq("#{rake_spec.name_tuple.lock_name} #{rake_checksums.map(&:to_lock).sort.join(",")}")
end
end
@@ -163,59 +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(:rake_sha512_checksum) do
- Bundler::Checksum.from_lock(
- "sha512=pVDn9GLmcFkz8vj1ueiVxj5uGKkAyaqYjEX8zG6L5O4BeVg3wANaKbQdpj/B82Nd/MHVszy6polHcyotUdwilQ==",
- "#{lockfile_path}:20:17"
- )
- end
- let(:lockfile_contents) do
- super().sub(
- "sha256=",
- "sha512=pVDn9GLmcFkz8vj1ueiVxj5uGKkAyaqYjEX8zG6L5O4BeVg3wANaKbQdpj/B82Nd/MHVszy6polHcyotUdwilQ==,sha256="
- )
- end
- let(:rake_checksums) { [rake_sha256_checksum, rake_sha512_checksum] }
- include_examples "parsing"
- 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_sha256_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/mirror_spec.rb b/spec/bundler/bundler/mirror_spec.rb
index ba1c6ed413..1eaf1e9a8e 100644
--- a/spec/bundler/bundler/mirror_spec.rb
+++ b/spec/bundler/bundler/mirror_spec.rb
@@ -36,12 +36,12 @@ RSpec.describe Bundler::Settings::Mirror do
it "takes a string for the uri but returns an uri object" do
mirror.uri = "http://localhost:9292"
- expect(mirror.uri).to eq(Gem::URI("http://localhost:9292"))
+ expect(mirror.uri).to eq(Bundler::URI("http://localhost:9292"))
end
it "takes an uri object for the uri" do
- mirror.uri = Gem::URI("http://localhost:9293")
- expect(mirror.uri).to eq(Gem::URI("http://localhost:9293"))
+ mirror.uri = Bundler::URI("http://localhost:9293")
+ expect(mirror.uri).to eq(Bundler::URI("http://localhost:9293"))
end
context "without a uri" do
@@ -145,7 +145,7 @@ RSpec.describe Bundler::Settings::Mirror do
end
RSpec.describe Bundler::Settings::Mirrors do
- let(:localhost_uri) { Gem::URI("http://localhost:9292") }
+ let(:localhost_uri) { Bundler::URI("http://localhost:9292") }
context "with a just created mirror" do
let(:mirrors) do
@@ -260,7 +260,7 @@ RSpec.describe Bundler::Settings::Mirrors do
before { mirrors.parse("mirror.all.fallback_timeout", "true") }
it "returns the source uri, not localhost" do
- expect(mirrors.for("http://whatever.com").uri).to eq(Gem::URI("http://whatever.com/"))
+ expect(mirrors.for("http://whatever.com").uri).to eq(Bundler::URI("http://whatever.com/"))
end
end
end
@@ -270,7 +270,7 @@ RSpec.describe Bundler::Settings::Mirrors do
context "without a fallback timeout" do
it "returns the uri that is not mirrored" do
- expect(mirrors.for("http://whatever.com").uri).to eq(Gem::URI("http://whatever.com/"))
+ expect(mirrors.for("http://whatever.com").uri).to eq(Bundler::URI("http://whatever.com/"))
end
it "returns localhost for rubygems.org" do
@@ -282,11 +282,11 @@ RSpec.describe Bundler::Settings::Mirrors do
before { mirrors.parse("mirror.http://rubygems.org/.fallback_timeout", "true") }
it "returns the uri that is not mirrored" do
- expect(mirrors.for("http://whatever.com").uri).to eq(Gem::URI("http://whatever.com/"))
+ expect(mirrors.for("http://whatever.com").uri).to eq(Bundler::URI("http://whatever.com/"))
end
it "returns rubygems.org for rubygems.org" do
- expect(mirrors.for("http://rubygems.org/").uri).to eq(Gem::URI("http://rubygems.org/"))
+ expect(mirrors.for("http://rubygems.org/").uri).to eq(Bundler::URI("http://rubygems.org/"))
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/dsl_spec.rb b/spec/bundler/bundler/plugin/dsl_spec.rb
index 235a549735..00e39dca69 100644
--- a/spec/bundler/bundler/plugin/dsl_spec.rb
+++ b/spec/bundler/bundler/plugin/dsl_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Bundler::Plugin::DSL do
it "adds #source with :type to list and also inferred_plugins list" do
expect(dsl).to receive(:plugin).with("bundler-source-news").once
- dsl.source("some_random_url", type: "news") {}
+ dsl.source("some_random_url", :type => "news") {}
expect(dsl.inferred_plugins).to eq(["bundler-source-news"])
end
@@ -31,8 +31,8 @@ RSpec.describe Bundler::Plugin::DSL do
it "registers a source type plugin only once for multiple declarations" do
expect(dsl).to receive(:plugin).with("bundler-source-news").and_call_original.once
- dsl.source("some_random_url", type: "news") {}
- dsl.source("another_random_url", type: "news") {}
+ dsl.source("some_random_url", :type => "news") {}
+ dsl.source("another_random_url", :type => "news") {}
end
end
end
diff --git a/spec/bundler/bundler/plugin/index_spec.rb b/spec/bundler/bundler/plugin/index_spec.rb
index e1f10a0db7..5a7047459f 100644
--- a/spec/bundler/bundler/plugin/index_spec.rb
+++ b/spec/bundler/bundler/plugin/index_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe Bundler::Plugin::Index do
before do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- gemfile "source 'https://gem.repo1'"
+ gemfile "source \"#{file_uri_for(gem_repo1)}\""
path = lib_path(plugin_name)
index.register_plugin("new-plugin", path.to_s, [path.join("lib").to_s], commands, sources, hooks)
end
diff --git a/spec/bundler/bundler/plugin/installer_spec.rb b/spec/bundler/bundler/plugin/installer_spec.rb
index 8e1879395a..2c50ee5afc 100644
--- a/spec/bundler/bundler/plugin/installer_spec.rb
+++ b/spec/bundler/bundler/plugin/installer_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Bundler::Plugin::Installer do
describe "cli install" do
it "uses Gem.sources when non of the source is provided" do
sources = double(:sources)
+ Bundler.settings # initialize it before we have to touch rubygems.ext_lock
allow(Gem).to receive(:sources) { sources }
allow(installer).to receive(:install_rubygems).
@@ -20,15 +21,15 @@ RSpec.describe Bundler::Plugin::Installer do
allow(installer).to receive(:install_git).
and_return("new-plugin" => spec)
- expect(installer.install(["new-plugin"], git: "https://some.ran/dom")).
+ expect(installer.install(["new-plugin"], :git => "https://some.ran/dom")).
to eq("new-plugin" => spec)
end
it "returns the installed spec after installing local git plugins" do
- allow(installer).to receive(:install_git).
+ allow(installer).to receive(:install_local_git).
and_return("new-plugin" => spec)
- expect(installer.install(["new-plugin"], git: "/phony/path/repo")).
+ expect(installer.install(["new-plugin"], :local_git => "/phony/path/repo")).
to eq("new-plugin" => spec)
end
@@ -36,7 +37,7 @@ RSpec.describe Bundler::Plugin::Installer do
allow(installer).to receive(:install_rubygems).
and_return("new-plugin" => spec)
- expect(installer.install(["new-plugin"], source: "https://some.ran/dom")).
+ expect(installer.install(["new-plugin"], :source => "https://some.ran/dom")).
to eq("new-plugin" => spec)
end
end
@@ -51,13 +52,13 @@ RSpec.describe Bundler::Plugin::Installer do
context "git plugins" do
before do
- build_git "ga-plugin", path: lib_path("ga-plugin") do |s|
+ build_git "ga-plugin", :path => lib_path("ga-plugin") do |s|
s.write "plugins.rb"
end
end
let(:result) do
- installer.install(["ga-plugin"], git: lib_path("ga-plugin").to_s)
+ installer.install(["ga-plugin"], :git => file_uri_for(lib_path("ga-plugin")))
end
it "returns the installed spec after installing" do
@@ -74,13 +75,13 @@ RSpec.describe Bundler::Plugin::Installer do
context "local git plugins" do
before do
- build_git "ga-plugin", path: lib_path("ga-plugin") do |s|
+ build_git "ga-plugin", :path => lib_path("ga-plugin") do |s|
s.write "plugins.rb"
end
end
let(:result) do
- installer.install(["ga-plugin"], git: lib_path("ga-plugin").to_s)
+ installer.install(["ga-plugin"], :local_git => lib_path("ga-plugin").to_s)
end
it "returns the installed spec after installing" do
@@ -97,7 +98,7 @@ RSpec.describe Bundler::Plugin::Installer do
context "rubygems plugins" do
let(:result) do
- installer.install(["re-plugin"], source: file_uri_for(gem_repo2))
+ installer.install(["re-plugin"], :source => file_uri_for(gem_repo2))
end
it "returns the installed spec after installing " do
@@ -112,7 +113,7 @@ RSpec.describe Bundler::Plugin::Installer do
context "multiple plugins" do
let(:result) do
- installer.install(["re-plugin", "ma-plugin"], source: file_uri_for(gem_repo2))
+ installer.install(["re-plugin", "ma-plugin"], :source => file_uri_for(gem_repo2))
end
it "returns the installed spec after installing " do
diff --git a/spec/bundler/bundler/plugin_spec.rb b/spec/bundler/bundler/plugin_spec.rb
index 3ac7b251a3..d28479cf31 100644
--- a/spec/bundler/bundler/plugin_spec.rb
+++ b/spec/bundler/bundler/plugin_spec.rb
@@ -9,11 +9,11 @@ RSpec.describe Bundler::Plugin do
let(:spec2) { double(:spec2) }
before do
- build_lib "new-plugin", path: lib_path("new-plugin") do |s|
+ build_lib "new-plugin", :path => lib_path("new-plugin") do |s|
s.write "plugins.rb"
end
- build_lib "another-plugin", path: lib_path("another-plugin") do |s|
+ build_lib "another-plugin", :path => lib_path("another-plugin") do |s|
s.write "plugins.rb"
end
@@ -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
@@ -247,7 +247,7 @@ RSpec.describe Bundler::Plugin do
end
it "returns plugin dir in app .bundle path" do
- expect(subject.root).to eq(bundled_app(".bundle/plugin"))
+ expect(subject.root).to eq(bundled_app.join(".bundle/plugin"))
end
end
@@ -257,7 +257,7 @@ RSpec.describe Bundler::Plugin do
end
it "returns plugin dir in global bundle path" do
- expect(subject.root).to eq(home(".bundle/plugin"))
+ expect(subject.root).to eq(home.join(".bundle/plugin"))
end
end
end
@@ -275,7 +275,7 @@ RSpec.describe Bundler::Plugin do
describe "#hook" do
before do
path = lib_path("foo-plugin")
- build_lib "foo-plugin", path: path do |s|
+ build_lib "foo-plugin", :path => path do |s|
s.write "plugins.rb", code
end
diff --git a/spec/bundler/bundler/remote_specification_spec.rb b/spec/bundler/bundler/remote_specification_spec.rb
index f35b231d58..921a47a2d3 100644
--- a/spec/bundler/bundler/remote_specification_spec.rb
+++ b/spec/bundler/bundler/remote_specification_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Bundler::RemoteSpecification do
end
describe "#fetch_platform" do
- let(:remote_spec) { double(:remote_spec, platform: "jruby") }
+ let(:remote_spec) { double(:remote_spec, :platform => "jruby") }
before { allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec) }
@@ -113,7 +113,7 @@ RSpec.describe Bundler::RemoteSpecification do
context "comparing a non sortable object" do
let(:other) { Object.new }
- let(:remote_spec) { double(:remote_spec, platform: "jruby") }
+ let(:remote_spec) { double(:remote_spec, :platform => "jruby") }
before do
allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
@@ -127,8 +127,8 @@ RSpec.describe Bundler::RemoteSpecification do
end
describe "#__swap__" do
- let(:spec) { double(:spec, dependencies: []) }
- let(:new_spec) { double(:new_spec, dependencies: [], runtime_dependencies: []) }
+ let(:spec) { double(:spec, :dependencies => []) }
+ let(:new_spec) { double(:new_spec, :dependencies => [], :runtime_dependencies => []) }
before { subject.instance_variable_set(:@_remote_specification, spec) }
@@ -157,7 +157,7 @@ RSpec.describe Bundler::RemoteSpecification do
describe "method missing" do
context "and is present in Gem::Specification" do
- let(:remote_spec) { double(:remote_spec, authors: "abcd") }
+ let(:remote_spec) { double(:remote_spec, :authors => "abcd") }
before do
allow(subject).to receive(:_remote_specification).and_return(remote_spec)
@@ -172,7 +172,7 @@ RSpec.describe Bundler::RemoteSpecification do
describe "respond to missing?" do
context "and is present in Gem::Specification" do
- let(:remote_spec) { double(:remote_spec, authors: "abcd") }
+ let(:remote_spec) { double(:remote_spec, :authors => "abcd") }
before do
allow(subject).to receive(:_remote_specification).and_return(remote_spec)
diff --git a/spec/bundler/bundler/resolver/candidate_spec.rb b/spec/bundler/bundler/resolver/candidate_spec.rb
index aefad3316e..cd52c867c4 100644
--- a/spec/bundler/bundler/resolver/candidate_spec.rb
+++ b/spec/bundler/bundler/resolver/candidate_spec.rb
@@ -2,19 +2,20 @@
RSpec.describe Bundler::Resolver::Candidate do
it "compares fine" do
- version1 = described_class.new("1.12.5", priority: -1)
- version2 = described_class.new("1.12.5", priority: 1)
+ version1 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::RUBY }])
+ version2 = described_class.new("1.12.5") # passing no specs creates a platform specific candidate, so sorts higher
- expect(version2 > version1).to be true
+ expect(version2 >= version1).to be true
- version1 = described_class.new("1.12.5")
- version2 = described_class.new("1.12.5")
+ expect(version1.generic! == version2.generic!).to be true
+ expect(version1.platform_specific! == version2.platform_specific!).to be true
- expect(version2 == version1).to be true
+ expect(version1.platform_specific! >= version2.generic!).to be true
+ expect(version2.platform_specific! >= version1.generic!).to be true
- version1 = described_class.new("1.12.5", priority: 1)
- version2 = described_class.new("1.12.5", priority: -1)
+ version1 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::RUBY }])
+ version2 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::X64_LINUX }])
- expect(version2 < version1).to be true
+ expect(version2 >= version1).to be true
end
end
diff --git a/spec/bundler/bundler/retry_spec.rb b/spec/bundler/bundler/retry_spec.rb
index ffbc078074..b893580d72 100644
--- a/spec/bundler/bundler/retry_spec.rb
+++ b/spec/bundler/bundler/retry_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe Bundler::Retry do
it "print error message with newlines" do
allow(Bundler.ui).to receive(:debug?).and_return(false)
expect(Bundler.ui).to receive(:info).with("").twice
- expect(Bundler.ui).to receive(:warn).with(failure_message, true)
+ expect(Bundler.ui).to receive(:warn).with(failure_message, false)
expect do
Bundler::Retry.new("test", [], 1).attempt do
diff --git a/spec/bundler/bundler/ruby_dsl_spec.rb b/spec/bundler/bundler/ruby_dsl_spec.rb
index c5ebbdf4db..bc1ca98457 100644
--- a/spec/bundler/bundler/ruby_dsl_spec.rb
+++ b/spec/bundler/bundler/ruby_dsl_spec.rb
@@ -7,37 +7,28 @@ RSpec.describe Bundler::RubyDsl do
include Bundler::RubyDsl
attr_reader :ruby_version
- attr_accessor :gemfile
end
let(:dsl) { MockDSL.new }
let(:ruby_version) { "2.0.0" }
- let(:ruby_version_arg) { ruby_version }
let(:version) { "2.0.0" }
let(:engine) { "jruby" }
let(:engine_version) { "9000" }
let(:patchlevel) { "100" }
let(:options) do
- { patchlevel: patchlevel,
- engine: engine,
- engine_version: engine_version }
+ { :patchlevel => patchlevel,
+ :engine => engine,
+ :engine_version => engine_version }
end
- let(:project_root) { Pathname.new("/path/to/project") }
- let(:gemfile) { project_root.join("Gemfile") }
- 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 << options
-
+ args = Array(ruby_version) + [options]
dsl.ruby(*args)
end
end
subject do
- dsl.gemfile = gemfile
invoke.call
dsl.ruby_version
end
@@ -68,19 +59,10 @@ 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
- expect { subject }.to raise_error(Bundler::InvalidArgumentError)
+ expect { subject }.to raise_error(ArgumentError)
end
end
@@ -109,94 +91,5 @@ RSpec.describe Bundler::RubyDsl do
it_behaves_like "it stores the ruby version"
end
end
-
- context "with a file option" do
- let(:file) { ".ruby-version" }
- let(:ruby_version_file_path) { gemfile.dirname.join(file) }
- let(:options) do
- { file: file,
- patchlevel: patchlevel,
- engine: engine,
- engine_version: engine_version }
- end
- let(:ruby_version_arg) { nil }
- let(:file_content) { "#{version}\n" }
-
- before do
- allow(Bundler).to receive(:read_file) do |path|
- raise Errno::ENOENT, <<~ERROR unless path == ruby_version_file_path
- #{file} not found in specs:
- expected: #{ruby_version_file_path}
- received: #{path}
- ERROR
- file_content
- end
- end
-
- it_behaves_like "it stores the ruby version"
-
- context "with the Gemfile ruby file: path is relative to the Gemfile in a subdir" do
- let(:gemfile) { project_root.join("subdir", "Gemfile") }
- let(:file) { "../.ruby-version" }
- let(:ruby_version_file_path) { gemfile.dirname.join(file) }
-
- it_behaves_like "it stores the ruby version"
- end
-
- context "with bundler root in a subdir of the project" do
- let(:project_root) { Pathname.new("/path/to/project/subdir") }
- let(:gemfile) { project_root.parent.join("Gemfile") }
-
- it_behaves_like "it stores the ruby version"
- end
-
- 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 }
-
- 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(Bundler::InvalidArgumentError, "2.0.0@gemset is not a valid requirement on the Ruby version")
- 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"
- end
- end
- end
end
end
diff --git a/spec/bundler/bundler/ruby_version_spec.rb b/spec/bundler/bundler/ruby_version_spec.rb
index 39d0571361..f1df12294d 100644
--- a/spec/bundler/bundler/ruby_version_spec.rb
+++ b/spec/bundler/bundler/ruby_version_spec.rb
@@ -400,19 +400,19 @@ RSpec.describe "Bundler::RubyVersion and its subclasses" do
let(:bundler_system_ruby_version) { subject }
around do |example|
- if Bundler::RubyVersion.instance_variable_defined?("@system")
+ if Bundler::RubyVersion.instance_variable_defined?("@ruby_version")
begin
- old_ruby_version = Bundler::RubyVersion.instance_variable_get("@system")
- Bundler::RubyVersion.remove_instance_variable("@system")
+ old_ruby_version = Bundler::RubyVersion.instance_variable_get("@ruby_version")
+ Bundler::RubyVersion.remove_instance_variable("@ruby_version")
example.run
ensure
- Bundler::RubyVersion.instance_variable_set("@system", old_ruby_version)
+ Bundler::RubyVersion.instance_variable_set("@ruby_version", old_ruby_version)
end
else
begin
example.run
ensure
- Bundler::RubyVersion.remove_instance_variable("@system")
+ Bundler::RubyVersion.remove_instance_variable("@ruby_version")
end
end
end
diff --git a/spec/bundler/bundler/rubygems_integration_spec.rb b/spec/bundler/bundler/rubygems_integration_spec.rb
index 81859d10f2..369f28fcef 100644
--- a/spec/bundler/bundler/rubygems_integration_spec.rb
+++ b/spec/bundler/bundler/rubygems_integration_spec.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
RSpec.describe Bundler::RubygemsIntegration do
+ it "uses the same chdir lock as rubygems" do
+ expect(Bundler.rubygems.ext_lock).to eq(Gem::Ext::Builder::CHDIR_MONITOR)
+ end
+
context "#validate" do
let(:spec) do
Gem::Specification.new do |s|
@@ -11,14 +15,14 @@ RSpec.describe Bundler::RubygemsIntegration do
end
subject { Bundler.rubygems.validate(spec) }
- it "validates for resolution" do
- expect(spec).to receive(:validate_for_resolution)
+ it "validates with packaging mode disabled" do
+ expect(spec).to receive(:validate).with(false)
subject
end
context "with an invalid spec" do
before do
- expect(spec).to receive(:validate_for_resolution).
+ expect(spec).to receive(:validate).with(false).
and_raise(Gem::InvalidSpecificationException.new("TODO is not an author"))
end
@@ -32,7 +36,7 @@ RSpec.describe Bundler::RubygemsIntegration do
describe "#download_gem" do
let(:bundler_retry) { double(Bundler::Retry) }
- let(:uri) { Gem::URI.parse("https://foo.bar") }
+ let(:uri) { Bundler::URI.parse("https://foo.bar") }
let(:cache_dir) { "#{Gem.path.first}/cache" }
let(:spec) do
spec = Gem::Specification.new("Foo", Gem::Version.new("2.5.2"))
@@ -42,12 +46,14 @@ RSpec.describe Bundler::RubygemsIntegration do
let(:fetcher) { double("gem_remote_fetcher") }
it "successfully downloads gem with retries" do
+ expect(Bundler.rubygems).to receive(:gem_remote_fetcher).and_return(fetcher)
+ expect(fetcher).to receive(:headers=).with({ "X-Gemfile-Source" => "https://foo.bar" })
expect(Bundler::Retry).to receive(:new).with("download gem from #{uri}/").
and_return(bundler_retry)
expect(bundler_retry).to receive(:attempts).and_yield
expect(fetcher).to receive(:cache_update_path)
- Bundler.rubygems.download_gem(spec, uri, cache_dir, fetcher)
+ Bundler.rubygems.download_gem(spec, uri, cache_dir)
end
end
@@ -58,36 +64,30 @@ RSpec.describe Bundler::RubygemsIntegration do
let(:prerelease_specs_response) { Marshal.dump(["prerelease_specs"]) }
context "when a rubygems source mirror is set" do
- let(:orig_uri) { Gem::URI("http://zombo.com") }
- let(:remote_with_mirror) { double("remote", uri: uri, original_uri: orig_uri) }
+ let(:orig_uri) { Bundler::URI("http://zombo.com") }
+ let(:remote_with_mirror) { double("remote", :uri => uri, :original_uri => orig_uri) }
it "sets the 'X-Gemfile-Source' header containing the original source" do
+ expect(Bundler.rubygems).to receive(:gem_remote_fetcher).twice.and_return(fetcher)
+ expect(fetcher).to receive(:headers=).with({ "X-Gemfile-Source" => "http://zombo.com" }).twice
expect(fetcher).to receive(:fetch_path).with(uri + "specs.4.8.gz").and_return(specs_response)
expect(fetcher).to receive(:fetch_path).with(uri + "prerelease_specs.4.8.gz").and_return(prerelease_specs_response)
- result = Bundler.rubygems.fetch_all_remote_specs(remote_with_mirror, fetcher)
+ result = Bundler.rubygems.fetch_all_remote_specs(remote_with_mirror)
expect(result).to eq(%w[specs prerelease_specs])
end
end
context "when there is no rubygems source mirror set" do
- let(:remote_no_mirror) { double("remote", uri: uri, original_uri: nil) }
+ let(:remote_no_mirror) { double("remote", :uri => uri, :original_uri => nil) }
it "does not set the 'X-Gemfile-Source' header" do
+ expect(Bundler.rubygems).to receive(:gem_remote_fetcher).twice.and_return(fetcher)
+ expect(fetcher).to_not receive(:headers=)
expect(fetcher).to receive(:fetch_path).with(uri + "specs.4.8.gz").and_return(specs_response)
expect(fetcher).to receive(:fetch_path).with(uri + "prerelease_specs.4.8.gz").and_return(prerelease_specs_response)
- result = Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror, fetcher)
+ result = Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror)
expect(result).to eq(%w[specs prerelease_specs])
end
end
-
- context "when loading an unexpected class" do
- let(:remote_no_mirror) { double("remote", uri: uri, original_uri: nil) }
- let(:unexpected_specs_response) { Marshal.dump(3) }
-
- it "raises a MarshalError error" do
- expect(fetcher).to receive(:fetch_path).with(uri + "specs.4.8.gz").and_return(unexpected_specs_response)
- expect { Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror, fetcher) }.to raise_error(Bundler::MarshalError, /unexpected class/i)
- end
- 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/settings_spec.rb b/spec/bundler/bundler/settings_spec.rb
index b7db548cf9..4636993d9f 100644
--- a/spec/bundler/bundler/settings_spec.rb
+++ b/spec/bundler/bundler/settings_spec.rb
@@ -6,18 +6,12 @@ RSpec.describe Bundler::Settings do
subject(:settings) { described_class.new(bundled_app) }
describe "#set_local" do
- context "root is nil" do
+ context "when the local config file is not found" do
subject(:settings) { described_class.new(nil) }
- before do
- allow(Pathname).to receive(:new).and_call_original
- allow(Pathname).to receive(:new).with(".bundle").and_return home(".bundle")
- end
-
- it "works" do
- subject.set_local("foo", "bar")
-
- expect(subject["foo"]).to eq("bar")
+ it "raises a GemfileNotFound error with explanation" do
+ expect { subject.set_local("foo", "bar") }.
+ to raise_error(Bundler::GemfileNotFound, "Could not locate Gemfile")
end
end
end
@@ -137,7 +131,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
Bundler.settings.set_command_option :no_install, true
- Bundler.settings.temporary(no_install: false) do
+ Bundler.settings.temporary(:no_install => false) do
expect(Bundler.settings[:no_install]).to eq false
end
@@ -153,12 +147,12 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
context "when called without a block" do
it "leaves the setting changed" do
- Bundler.settings.temporary(foo: :random)
+ Bundler.settings.temporary(:foo => :random)
expect(Bundler.settings[:foo]).to eq "random"
end
it "returns nil" do
- expect(Bundler.settings.temporary(foo: :bar)).to be_nil
+ expect(Bundler.settings.temporary(:foo => :bar)).to be_nil
end
end
end
@@ -185,7 +179,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
describe "#mirror_for" do
- let(:uri) { Gem::URI("https://rubygems.org/") }
+ let(:uri) { Bundler::URI("https://rubygems.org/") }
context "with no configured mirror" do
it "returns the original URI" do
@@ -198,7 +192,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
context "with a configured mirror" do
- let(:mirror_uri) { Gem::URI("https://rubygems-mirror.org/") }
+ let(:mirror_uri) { Bundler::URI("https://rubygems-mirror.org/") }
before { settings.set_local "mirror.https://rubygems.org/", mirror_uri.to_s }
@@ -219,7 +213,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
context "with a file URI" do
- let(:mirror_uri) { Gem::URI("file:/foo/BAR/baz/qUx/") }
+ let(:mirror_uri) { Bundler::URI("file:/foo/BAR/baz/qUx/") }
it "returns the mirror URI" do
expect(settings.mirror_for(uri)).to eq(mirror_uri)
@@ -237,7 +231,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
describe "#credentials_for" do
- let(:uri) { Gem::URI("https://gemserver.example.org/") }
+ let(:uri) { Bundler::URI("https://gemserver.example.org/") }
let(:credentials) { "username:password" }
context "with no configured credentials" do
@@ -297,7 +291,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
it "reads older keys without trailing slashes" do
settings.set_local "mirror.https://rubygems.org", "http://rubygems-mirror.org"
expect(settings.mirror_for("https://rubygems.org/")).to eq(
- Gem::URI("http://rubygems-mirror.org/")
+ Bundler::URI("http://rubygems-mirror.org/")
)
end
@@ -316,8 +310,8 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
let(:settings) { described_class.new(bundled_app(".bundle")) }
it "converts older keys without double underscore" do
- config("BUNDLE_MY__PERSONAL.MYRACK" => "~/Work/git/myrack")
- expect(settings["my.personal.myrack"]).to eq("~/Work/git/myrack")
+ config("BUNDLE_MY__PERSONAL.RACK" => "~/Work/git/rack")
+ expect(settings["my.personal.rack"]).to eq("~/Work/git/rack")
end
it "converts older keys without trailing slashes and double underscore" do
@@ -325,15 +319,6 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
expect(settings["mirror.https://rubygems.org/"]).to eq("http://rubygems-mirror.org")
end
- it "ignores commented out keys" do
- create_file bundled_app(".bundle/config"), <<~C
- # BUNDLE_MY-PERSONAL-SERVER__ORG: my-personal-server.org
- C
-
- expect(Bundler.ui).not_to receive(:warn)
- expect(settings.all).to be_empty
- end
-
it "converts older keys with dashes" do
config("BUNDLE_MY-PERSONAL-SERVER__ORG" => "my-personal-server.org")
expect(Bundler.ui).to receive(:warn).with(
diff --git a/spec/bundler/bundler/shared_helpers_spec.rb b/spec/bundler/bundler/shared_helpers_spec.rb
index 918f73b337..e1c5122564 100644
--- a/spec/bundler/bundler/shared_helpers_spec.rb
+++ b/spec/bundler/bundler/shared_helpers_spec.rb
@@ -1,8 +1,12 @@
# frozen_string_literal: true
RSpec.describe Bundler::SharedHelpers do
+ let(:ext_lock_double) { double(:ext_lock) }
+
before do
pwd_stub
+ allow(Bundler.rubygems).to receive(:ext_lock).and_return(ext_lock_double)
+ allow(ext_lock_double).to receive(:synchronize) {|&block| block.call }
end
let(:pwd_stub) { allow(subject).to receive(:pwd).and_return(bundled_app) }
@@ -238,12 +242,14 @@ 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
shared_examples_for "ENV['BUNDLER_SETUP'] gets set correctly" do
it "ensures bundler/setup is set in ENV['BUNDLER_SETUP']" do
+ skip "Does not play well with DidYouMean being a bundled gem instead of a default gem in Ruby 2.6" if RUBY_VERSION < "2.7"
+
subject.set_bundle_environment
expect(ENV["BUNDLER_SETUP"]).to eq("#{source_lib_dir}/bundler/setup")
end
@@ -284,7 +290,7 @@ RSpec.describe Bundler::SharedHelpers do
if Gem.respond_to?(:path_separator)
allow(Gem).to receive(:path_separator).and_return(":")
else
- stub_const("File::PATH_SEPARATOR", ":")
+ stub_const("File::PATH_SEPARATOR", ":".freeze)
end
allow(Bundler).to receive(:bundle_path) { Pathname.new("so:me/dir/bin") }
expect { subject.send(:validate_bundle_path) }.to raise_error(
@@ -361,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
@@ -518,34 +503,4 @@ RSpec.describe Bundler::SharedHelpers do
end
end
end
-
- describe "#major_deprecation" do
- before { allow(Bundler).to receive(:bundler_major_version).and_return(37) }
- before { allow(Bundler.ui).to receive(:warn) }
-
- it "prints and raises nothing below the deprecated major version" do
- subject.major_deprecation(38, "Message")
- subject.major_deprecation(39, "Message", removed_message: "Removal", print_caller_location: true)
- expect(Bundler.ui).not_to have_received(:warn)
- end
-
- it "prints but does not raise _at_ the deprecated major version" do
- subject.major_deprecation(37, "Message")
- subject.major_deprecation(37, "Message", removed_message: "Removal")
- expect(Bundler.ui).to have_received(:warn).with("[DEPRECATED] Message").twice
-
- subject.major_deprecation(37, "Message", print_caller_location: true)
- expect(Bundler.ui).to have_received(:warn).
- with(a_string_matching(/^\[DEPRECATED\] Message \(called at .*:\d+\)$/))
- end
-
- it "raises the appropriate errors when _past_ the deprecated major version" do
- expect { subject.major_deprecation(36, "Message") }.
- to raise_error(Bundler::DeprecatedError, "[REMOVED] Message")
- expect { subject.major_deprecation(36, "Message", removed_message: "Removal") }.
- to raise_error(Bundler::DeprecatedError, "[REMOVED] Removal")
- expect { subject.major_deprecation(35, "Message", removed_message: "Removal", print_caller_location: true) }.
- to raise_error(Bundler::DeprecatedError, /^\[REMOVED\] Removal \(called at .*:\d+\)$/)
- end
- end
end
diff --git a/spec/bundler/bundler/source/git/git_proxy_spec.rb b/spec/bundler/bundler/source/git/git_proxy_spec.rb
index f7c883eed4..841b8651e4 100644
--- a/spec/bundler/bundler/source/git/git_proxy_spec.rb
+++ b/spec/bundler/bundler/source/git/git_proxy_spec.rb
@@ -3,84 +3,32 @@
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).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch", "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s)
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).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch", "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s)
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).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch", "--", uri, path.to_s)
subject.checkout
end
end
@@ -88,10 +36,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).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:git_retry).with("clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch", "--", original, path.to_s)
+ subject.checkout
end
end
end
@@ -99,46 +47,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).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).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).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 +94,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).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).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).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
@@ -193,22 +141,8 @@ RSpec.describe Bundler::Source::Git::GitProxy do
FileUtils.chmod("+x", file)
- bundle :lock, raise_on_error: false
+ bundle :lock, :raise_on_error => false
expect(Pathname.new(bundled_app("canary"))).not_to exist
end
-
- context "URI is HTTP" do
- let(:uri) { "http://github.com/rubygems/rubygems.git" }
- let(:without_depth_arguments) { ["clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--single-branch"] }
- let(:fail_clone_result) { double(Process::Status, success?: false) }
-
- it "retries without --depth when git url is http and fails" do
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- allow(git_proxy).to receive(:capture).with([*base_clone_args, "--", uri, path.to_s], nil).and_return(["", "dumb http transport does not support shallow capabilities", fail_clone_result])
- expect(git_proxy).to receive(:capture).with([*without_depth_arguments, "--", uri, path.to_s], nil).and_return(["", "", clone_result])
-
- subject.checkout
- end
- end
end
diff --git a/spec/bundler/bundler/source/git_spec.rb b/spec/bundler/bundler/source/git_spec.rb
index feef54bbf4..ed6dc3cd29 100644
--- a/spec/bundler/bundler/source/git_spec.rb
+++ b/spec/bundler/bundler/source/git_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Bundler::Source::Git do
context "when the source has a reference" do
let(:git_proxy_stub) do
- instance_double(Bundler::Source::Git::GitProxy, revision: "123abc", branch: "v1.0.0")
+ instance_double(Bundler::Source::Git::GitProxy, :revision => "123abc", :branch => "v1.0.0")
end
let(:options) do
{ "uri" => uri, "ref" => "v1.0.0" }
@@ -55,7 +55,7 @@ RSpec.describe Bundler::Source::Git do
context "when the source has both reference and glob specifiers" do
let(:git_proxy_stub) do
- instance_double(Bundler::Source::Git::GitProxy, revision: "123abc", branch: "v1.0.0")
+ instance_double(Bundler::Source::Git::GitProxy, :revision => "123abc", :branch => "v1.0.0")
end
let(:options) do
{ "uri" => uri, "ref" => "v1.0.0", "glob" => "gems/foo/*.gemspec" }
diff --git a/spec/bundler/bundler/source/rubygems/remote_spec.rb b/spec/bundler/bundler/source/rubygems/remote_spec.rb
index 56f3bee459..07ce4f968e 100644
--- a/spec/bundler/bundler/source/rubygems/remote_spec.rb
+++ b/spec/bundler/bundler/source/rubygems/remote_spec.rb
@@ -11,8 +11,8 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
allow(Digest(:MD5)).to receive(:hexdigest).with(duck_type(:to_s)) {|string| "MD5HEX(#{string})" }
end
- let(:uri_no_auth) { Gem::URI("https://gems.example.com") }
- let(:uri_with_auth) { Gem::URI("https://#{credentials}@gems.example.com") }
+ let(:uri_no_auth) { Bundler::URI("https://gems.example.com") }
+ let(:uri_with_auth) { Bundler::URI("https://#{credentials}@gems.example.com") }
let(:credentials) { "username:password" }
context "when the original URI has no credentials" do
@@ -89,11 +89,11 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
context "when the original URI has only a username" do
- let(:uri) { Gem::URI("https://SeCrEt-ToKeN@gem.fury.io/me/") }
+ let(:uri) { Bundler::URI("https://SeCrEt-ToKeN@gem.fury.io/me/") }
describe "#anonymized_uri" do
it "returns the URI without username and password" do
- expect(remote(uri).anonymized_uri).to eq(Gem::URI("https://gem.fury.io/me/"))
+ expect(remote(uri).anonymized_uri).to eq(Bundler::URI("https://gem.fury.io/me/"))
end
end
@@ -105,9 +105,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
context "when a mirror with inline credentials is configured for the URI" do
- let(:uri) { Gem::URI("https://rubygems.org/") }
- let(:mirror_uri_with_auth) { Gem::URI("https://username:password@rubygems-mirror.org/") }
- let(:mirror_uri_no_auth) { Gem::URI("https://rubygems-mirror.org/") }
+ let(:uri) { Bundler::URI("https://rubygems.org/") }
+ let(:mirror_uri_with_auth) { Bundler::URI("https://username:password@rubygems-mirror.org/") }
+ let(:mirror_uri_no_auth) { Bundler::URI("https://rubygems-mirror.org/") }
before { Bundler.settings.temporary("mirror.https://rubygems.org/" => mirror_uri_with_auth.to_s) }
@@ -131,9 +131,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
context "when a mirror with configured credentials is configured for the URI" do
- let(:uri) { Gem::URI("https://rubygems.org/") }
- let(:mirror_uri_with_auth) { Gem::URI("https://#{credentials}@rubygems-mirror.org/") }
- let(:mirror_uri_no_auth) { Gem::URI("https://rubygems-mirror.org/") }
+ let(:uri) { Bundler::URI("https://rubygems.org/") }
+ let(:mirror_uri_with_auth) { Bundler::URI("https://#{credentials}@rubygems-mirror.org/") }
+ let(:mirror_uri_no_auth) { Bundler::URI("https://rubygems-mirror.org/") }
before do
Bundler.settings.temporary("mirror.https://rubygems.org/" => mirror_uri_no_auth.to_s)
diff --git a/spec/bundler/bundler/source_list_spec.rb b/spec/bundler/bundler/source_list_spec.rb
index 13453cb2a3..f860e9ff58 100644
--- a/spec/bundler/bundler/source_list_spec.rb
+++ b/spec/bundler/bundler/source_list_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe Bundler::SourceList do
end
it "ignores git protocols on request" do
- Bundler.settings.temporary("git.allow_insecure": true)
+ Bundler.settings.temporary(:"git.allow_insecure" => true)
expect(Bundler.ui).to_not receive(:warn).with(msg)
source_list.add_git_source("uri" => "git://existing-git.org/path.git")
end
@@ -125,8 +125,8 @@ RSpec.describe Bundler::SourceList do
it "adds the provided remote to the beginning of the aggregate source" do
source_list.add_global_rubygems_remote("https://othersource.org")
expect(returned_source.remotes).to eq [
- Gem::URI("https://othersource.org/"),
- Gem::URI("https://rubygems.org/"),
+ Bundler::URI("https://othersource.org/"),
+ Bundler::URI("https://rubygems.org/"),
]
end
end
diff --git a/spec/bundler/bundler/source_spec.rb b/spec/bundler/bundler/source_spec.rb
index 3b49c37431..ceb369ecdb 100644
--- a/spec/bundler/bundler/source_spec.rb
+++ b/spec/bundler/bundler/source_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe Bundler::Source do
end
describe "#version_message" do
- let(:spec) { double(:spec, name: "nokogiri", version: ">= 1.6", platform: rb) }
+ let(:spec) { double(:spec, :name => "nokogiri", :version => ">= 1.6", :platform => rb) }
shared_examples_for "the lockfile specs are not relevant" do
it "should return a string with the spec name and version" do
@@ -32,19 +32,19 @@ RSpec.describe Bundler::Source do
context "when there are locked gems" do
context "that contain the relevant gem spec" do
context "without a version" do
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: nil) }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => nil) }
it_behaves_like "the lockfile specs are not relevant"
end
context "with the same version" do
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: ">= 1.6") }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => ">= 1.6") }
it_behaves_like "the lockfile specs are not relevant"
end
context "with a different version" do
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "< 1.5") }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => "< 1.5") }
context "with color", :no_color_tty do
before do
@@ -70,8 +70,8 @@ RSpec.describe Bundler::Source do
end
context "with a more recent version" do
- let(:spec) { double(:spec, name: "nokogiri", version: "1.6.1", platform: rb) }
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "1.7.0") }
+ let(:spec) { double(:spec, :name => "nokogiri", :version => "1.6.1", :platform => rb) }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => "1.7.0") }
context "with color", :no_color_tty do
before do
@@ -97,8 +97,8 @@ RSpec.describe Bundler::Source do
end
context "with an older version" do
- let(:spec) { double(:spec, name: "nokogiri", version: "1.7.1", platform: rb) }
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "1.7.0") }
+ let(:spec) { double(:spec, :name => "nokogiri", :version => "1.7.1", :platform => rb) }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => "1.7.0") }
context "with color", :no_color_tty do
before do
@@ -128,7 +128,7 @@ RSpec.describe Bundler::Source do
describe "#can_lock?" do
context "when the passed spec's source is equivalent" do
- let(:spec) { double(:spec, source: subject) }
+ let(:spec) { double(:spec, :source => subject) }
it "should return true" do
expect(subject.can_lock?(spec)).to be_truthy
@@ -136,7 +136,7 @@ RSpec.describe Bundler::Source do
end
context "when the passed spec's source is not equivalent" do
- let(:spec) { double(:spec, source: double(:other_source)) }
+ let(:spec) { double(:spec, :source => double(:other_source)) }
it "should return false" do
expect(subject.can_lock?(spec)).to be_falsey
diff --git a/spec/bundler/bundler/spec_set_spec.rb b/spec/bundler/bundler/spec_set_spec.rb
index c4b6676223..6fedd38b50 100644
--- a/spec/bundler/bundler/spec_set_spec.rb
+++ b/spec/bundler/bundler/spec_set_spec.rb
@@ -45,6 +45,24 @@ RSpec.describe Bundler::SpecSet do
end
end
+ describe "#merge" do
+ let(:other_specs) do
+ [
+ build_spec("f", "1.0"),
+ build_spec("g", "2.0"),
+ ].flatten
+ end
+
+ let(:other_spec_set) { described_class.new(other_specs) }
+
+ it "merges the items in each gemspec" do
+ new_spec_set = subject.merge(other_spec_set)
+ specs = new_spec_set.to_a.map(&:full_name)
+ expect(specs).to include("a-1.0")
+ expect(specs).to include("f-1.0")
+ end
+ end
+
describe "#to_a" do
it "returns the specs in order" do
expect(subject.to_a.map(&:full_name)).to eq %w[
diff --git a/spec/bundler/bundler/specifications/foo.gemspec b/spec/bundler/bundler/specifications/foo.gemspec
deleted file mode 100644
index 46eb068cd1..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 = ">= 3.0.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 beb966b3ce..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)
@@ -55,24 +44,4 @@ RSpec.describe Bundler::StubSpecification do
expect(stub.missing_extensions?).to be true
end
end
-
- describe "#activated?" do
- it "returns true after activation" do
- stub = described_class.from_stub(with_bundler_stub_spec)
-
- expect(stub.activated?).to be_falsey
- stub.activated = true
- expect(stub.activated?).to be true
- end
-
- it "returns true after activation if the underlying stub is a `Gem::StubSpecification`" do
- spec_path = File.join(File.dirname(__FILE__), "specifications", "foo.gemspec")
- gem_stub = Gem::StubSpecification.new(spec_path, File.dirname(__FILE__),"","")
- stub = described_class.from_stub(gem_stub)
-
- expect(stub.activated?).to be_falsey
- stub.activated = true
- expect(stub.activated?).to be true
- end
- end
end
diff --git a/spec/bundler/bundler/ui/shell_spec.rb b/spec/bundler/bundler/ui/shell_spec.rb
index 422c850a65..15120a8a41 100644
--- a/spec/bundler/bundler/ui/shell_spec.rb
+++ b/spec/bundler/bundler/ui/shell_spec.rb
@@ -10,13 +10,6 @@ RSpec.describe Bundler::UI::Shell do
it "prints to stdout" do
expect { subject.info("info") }.to output("info\n").to_stdout
end
-
- context "when output_stream is :stderr" do
- before { subject.output_stream = :stderr }
- it "prints to stderr" do
- expect { subject.info("info") }.to output("info\n").to_stderr
- end
- end
end
describe "#confirm" do
@@ -24,36 +17,19 @@ RSpec.describe Bundler::UI::Shell do
it "prints to stdout" do
expect { subject.confirm("confirm") }.to output("confirm\n").to_stdout
end
-
- context "when output_stream is :stderr" do
- before { subject.output_stream = :stderr }
- it "prints to stderr" do
- expect { subject.confirm("confirm") }.to output("confirm\n").to_stderr
- end
- end
end
describe "#warn" do
before { subject.level = "warn" }
- it "prints to stderr, implicitly adding a newline" do
+ it "prints to stderr" do
expect { subject.warn("warning") }.to output("warning\n").to_stderr
end
- it "can be told not to emit a newline" do
- expect { subject.warn("warning", false) }.to output("warning").to_stderr
- end
end
describe "#debug" do
it "prints to stdout" do
expect { subject.debug("debug") }.to output("debug\n").to_stdout
end
-
- context "when output_stream is :stderr" do
- before { subject.output_stream = :stderr }
- it "prints to stderr" do
- expect { subject.debug("debug") }.to output("debug\n").to_stderr
- end
- end
end
describe "#error" do
diff --git a/spec/bundler/bundler/uri_credentials_filter_spec.rb b/spec/bundler/bundler/uri_credentials_filter_spec.rb
index ed24744a1c..466c1b8594 100644
--- a/spec/bundler/bundler/uri_credentials_filter_spec.rb
+++ b/spec/bundler/bundler/uri_credentials_filter_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe Bundler::URICredentialsFilter do
let(:credentials) { "oauth_token:x-oauth-basic@" }
it "returns the uri without the oauth token" do
- expect(subject.credential_filtered_uri(uri).to_s).to eq(Gem::URI("https://x-oauth-basic@github.com/company/private-repo").to_s)
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(Bundler::URI("https://x-oauth-basic@github.com/company/private-repo").to_s)
end
it_behaves_like "original type of uri is maintained"
@@ -26,7 +26,7 @@ RSpec.describe Bundler::URICredentialsFilter do
let(:credentials) { "oauth_token:x@" }
it "returns the uri without the oauth token" do
- expect(subject.credential_filtered_uri(uri).to_s).to eq(Gem::URI("https://x@github.com/company/private-repo").to_s)
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(Bundler::URI("https://x@github.com/company/private-repo").to_s)
end
it_behaves_like "original type of uri is maintained"
@@ -37,7 +37,7 @@ RSpec.describe Bundler::URICredentialsFilter do
let(:credentials) { "username1:hunter3@" }
it "returns the uri without the password" do
- expect(subject.credential_filtered_uri(uri).to_s).to eq(Gem::URI("https://username1@github.com/company/private-repo").to_s)
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(Bundler::URI("https://username1@github.com/company/private-repo").to_s)
end
it_behaves_like "original type of uri is maintained"
@@ -55,7 +55,7 @@ RSpec.describe Bundler::URICredentialsFilter do
end
context "uri is a uri object" do
- let(:uri) { Gem::URI("https://#{credentials}github.com/company/private-repo") }
+ let(:uri) { Bundler::URI("https://#{credentials}github.com/company/private-repo") }
it_behaves_like "sensitive credentials in uri are filtered out"
end
@@ -90,7 +90,7 @@ RSpec.describe Bundler::URICredentialsFilter do
describe "#credential_filtered_string" do
let(:str_to_filter) { "This is a git message containing a uri #{uri}!" }
let(:credentials) { "" }
- let(:uri) { Gem::URI("https://#{credentials}github.com/company/private-repo") }
+ let(:uri) { Bundler::URI("https://#{credentials}github.com/company/private-repo") }
context "with a uri that contains credentials" do
let(:credentials) { "oauth_token:x-oauth-basic@" }
diff --git a/spec/bundler/bundler/yaml_serializer_spec.rb b/spec/bundler/bundler/yaml_serializer_spec.rb
index de437f764a..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,34 +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
-
- it "skip commented out words" do
- yaml = <<~YAML
- ---
- foo: bar
- buzz: foo # bar
- YAML
-
- hash = {
- "foo" => "bar",
- "buzz" => "foo",
- }
-
- expect(serializer.load(yaml)).to eq(hash)
- end
end
describe "against yaml lib" do
diff --git a/spec/bundler/cache/cache_path_spec.rb b/spec/bundler/cache/cache_path_spec.rb
index d5bd14965b..12385427b1 100644
--- a/spec/bundler/cache/cache_path_spec.rb
+++ b/spec/bundler/cache/cache_path_spec.rb
@@ -3,15 +3,15 @@
RSpec.describe "bundle package" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
context "with --cache-path" do
it "caches gems at given path" do
bundle :cache, "cache-path" => "vendor/cache-foo"
- expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache-foo/rack-1.0.0.gem")).to exist
end
end
@@ -19,14 +19,14 @@ RSpec.describe "bundle package" do
it "caches gems at given path" do
bundle "config set cache_path vendor/cache-foo"
bundle :cache
- expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache-foo/rack-1.0.0.gem")).to exist
end
end
context "with absolute --cache-path" do
it "caches gems at given path" do
- bundle :cache, "cache-path" => bundled_app("vendor/cache-foo")
- expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist
+ bundle :cache, "cache-path" => "/tmp/cache-foo"
+ expect(bundled_app("/tmp/cache-foo/rack-1.0.0.gem")).to exist
end
end
end
diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb
index a694df2700..63c00eba01 100644
--- a/spec/bundler/cache/gems_spec.rb
+++ b/spec/bundler/cache/gems_spec.rb
@@ -4,23 +4,23 @@ RSpec.describe "bundle cache" do
shared_examples_for "when there are only gemsources" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- system_gems "myrack-1.0.0", path: path
+ system_gems "rack-1.0.0", :path => path
bundle :cache
end
it "copies the .gem file to vendor/cache" do
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "uses the cache as a source when installing gems" do
- build_gem "omg", path: bundled_app("vendor/cache")
+ build_gem "omg", :path => bundled_app("vendor/cache")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "omg"
G
@@ -28,47 +28,47 @@ RSpec.describe "bundle cache" do
end
it "uses the cache as a source when installing gems with --local" do
- system_gems [], path: default_bundle_path
+ system_gems [], :path => default_bundle_path
bundle "install --local"
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "does not reinstall gems from the cache if they exist on the system" do
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache") do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "does not reinstall gems from the cache if they exist in the bundle" do
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache") do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
- bundle :install, local: true
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ bundle :install, :local => true
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "creates a lockfile" do
- cache_gems "myrack-1.0.0"
+ cache_gems "rack-1.0.0"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "cache"
@@ -93,97 +93,82 @@ RSpec.describe "bundle cache" do
let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" }
before :each do
- build_gem "json", default_json_version, to_system: true, default: true
- end
-
- context "when a remote gem is available for caching" do
- before do
- build_repo2 do
- build_gem "json", default_json_version
- end
+ build_repo2 do
+ build_gem "json", default_json_version
end
- it "uses remote gems when installing" do
- install_gemfile %(source "https://gem.repo2"; gem 'json', '#{default_json_version}'), verbose: true
- expect(out).to include("Installing json #{default_json_version}")
- end
+ build_gem "json", default_json_version, :to_system => true, :default => true
+ end
- it "does not use remote gems when installing with --local flag" do
- install_gemfile %(source "https://gem.repo2"; gem 'json', '#{default_json_version}'), verbose: true, local: true
- expect(out).to include("Using json #{default_json_version}")
- end
+ it "uses builtin gems when installing to system gems" do
+ bundle "config set path.system true"
+ install_gemfile %(source "#{file_uri_for(gem_repo1)}"; gem 'json', '#{default_json_version}'), :verbose => true
+ expect(out).to include("Using json #{default_json_version}")
+ end
- it "caches remote and builtin gems" do
- install_gemfile <<-G
- source "https://gem.repo2"
- gem 'json', '#{default_json_version}'
- gem 'myrack', '1.0.0'
- G
+ it "caches remote and builtin gems" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'json', '#{default_json_version}'
+ gem 'rack', '1.0.0'
+ G
- bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
- end
+ bundle :cache
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
+ end
- it "caches builtin gems when cache_all_platforms is set" do
- gemfile <<-G
- source "https://gem.repo2"
- gem "json"
- G
+ it "caches builtin gems when cache_all_platforms is set" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem "json"
+ G
- bundle "config set cache_all_platforms true"
+ bundle "config set cache_all_platforms true"
- bundle :cache
- expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
- end
+ bundle :cache
+ expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
+ end
- it "doesn't make remote request after caching the gem" do
- build_gem "builtin_gem_2", "1.0.2", path: bundled_app("vendor/cache"), default: true
+ it "doesn't make remote request after caching the gem" do
+ build_gem "builtin_gem_2", "1.0.2", :path => bundled_app("vendor/cache") do |s|
+ s.summary = "This builtin_gem is bundled with Ruby"
+ end
- install_gemfile <<-G
- source "https://gem.repo2"
- gem 'builtin_gem_2', '1.0.2'
- G
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'builtin_gem_2', '1.0.2'
+ G
- bundle "install --local"
- expect(the_bundle).to include_gems("builtin_gem_2 1.0.2")
- end
+ bundle "install --local"
+ expect(the_bundle).to include_gems("builtin_gem_2 1.0.2")
end
- context "when a remote gem is not available for caching" do
- it "warns, but uses builtin gems when installing to system gems" do
- bundle "config set path.system true"
- install_gemfile %(source "https://gem.repo1"; gem 'json', '#{default_json_version}'), verbose: true
- expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached")
- expect(out).to include("Using json #{default_json_version}")
- end
-
- it "errors when explicitly caching" do
- bundle "config set path.system true"
+ it "errors if the builtin gem isn't available to cache" do
+ bundle "config set path.system true"
- install_gemfile <<-G
- source "https://gem.repo1"
- gem 'json', '#{default_json_version}'
- G
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'json', '#{default_json_version}'
+ G
- bundle :cache, raise_on_error: false
- expect(exitstatus).to_not eq(0)
- expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached")
- end
+ bundle :cache, :raise_on_error => false
+ expect(exitstatus).to_not eq(0)
+ expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached")
end
end
describe "when there are also git sources" do
before do
build_git "foo"
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
- gem 'myrack'
+ gem 'rack'
G
end
@@ -193,7 +178,7 @@ RSpec.describe "bundle cache" do
system_gems []
bundle "install --local"
- expect(the_bundle).to include_gems("myrack 1.0.0", "foo 1.0")
+ expect(the_bundle).to include_gems("rack 1.0.0", "foo 1.0")
end
it "should not explode if the lockfile is not present" do
@@ -206,44 +191,41 @@ RSpec.describe "bundle cache" do
end
describe "when previously cached" do
- let :setup_main_repo do
+ before :each do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "actionpack"
G
bundle :cache
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("rack-1.0.0")).to exist
expect(cached_gem("actionpack-2.3.2")).to exist
expect(cached_gem("activesupport-2.3.2")).to exist
end
it "re-caches during install" do
- setup_main_repo
- cached_gem("myrack-1.0.0").rmtree
+ cached_gem("rack-1.0.0").rmtree
bundle :install
expect(out).to include("Updating files in vendor/cache")
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("rack-1.0.0")).to exist
end
it "adds and removes when gems are updated" do
- setup_main_repo
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
- bundle "update", all: true
- expect(cached_gem("myrack-1.2")).to exist
- expect(cached_gem("myrack-1.0.0")).not_to exist
+ bundle "update", :all => true
+ expect(cached_gem("rack-1.2")).to exist
+ expect(cached_gem("rack-1.0.0")).not_to exist
end
it "adds new gems and dependencies" do
- setup_main_repo
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
G
expect(cached_gem("rails-2.3.2")).to exist
@@ -251,26 +233,24 @@ RSpec.describe "bundle cache" do
end
it "removes .gems for removed gems and dependencies" do
- setup_main_repo
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("rack-1.0.0")).to exist
expect(cached_gem("actionpack-2.3.2")).not_to exist
expect(cached_gem("activesupport-2.3.2")).not_to exist
end
it "removes .gems when gem changes to git source" do
- setup_main_repo
- build_git "myrack"
+ build_git "rack"
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", :git => "#{lib_path("myrack-1.0")}"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", :git => "#{lib_path("rack-1.0")}"
gem "actionpack"
G
- expect(cached_gem("myrack-1.0.0")).not_to exist
+ expect(cached_gem("rack-1.0.0")).not_to exist
expect(cached_gem("actionpack-2.3.2")).to exist
expect(cached_gem("activesupport-2.3.2")).to exist
end
@@ -278,7 +258,7 @@ RSpec.describe "bundle cache" do
it "doesn't remove gems that are for another platform" do
simulate_platform "java" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
@@ -287,108 +267,36 @@ RSpec.describe "bundle cache" do
end
simulate_new_machine
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
- simulate_platform "x86-darwin-100" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
-
- expect(cached_gem("platform_specific-1.0-x86-darwin-100")).to exist
- expect(cached_gem("platform_specific-1.0-java")).to exist
- end
- end
-
- it "doesn't remove gems cached gems that don't match their remote counterparts, but also refuses to install and prints an error" do
- setup_main_repo
- cached_myrack = cached_gem("myrack-1.0.0")
- cached_myrack.rmtree
- build_gem "myrack", "1.0.0",
- path: cached_myrack.parent,
- rubygems_version: "1.3.2"
-
- simulate_new_machine
-
- FileUtils.rm bundled_app_lock
- bundle :install, raise_on_error: false
-
- expect(err).to eq <<~E.strip
- Bundler found mismatched checksums. This is a potential security risk.
- #{checksum_to_lock(gem_repo2, "myrack", "1.0.0")}
- from the API at https://gem.repo2/
- #{checksum_from_package(cached_myrack, "myrack", "1.0.0")}
- from the gem at #{cached_myrack}
-
- If you trust the API at https://gem.repo2/, to resolve this issue you can:
- 1. remove the gem at #{cached_myrack}
- 2. run `bundle install`
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
-
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("platform_specific-1.0-#{Bundler.local_platform}")).to exist
+ expect(cached_gem("platform_specific-1.0-java")).to exist
end
- it "raises an error when a cached gem is altered and produces a different checksum than the remote gem" do
- setup_main_repo
- cached_gem("myrack-1.0.0").rmtree
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
-
- checksums = checksums_section do |c|
- c.checksum gem_repo1, "myrack", "1.0.0"
- end
-
+ it "doesn't remove gems with mismatched :rubygems_version or :date" do
+ cached_gem("rack-1.0.0").rmtree
+ build_gem "rack", "1.0.0",
+ :path => bundled_app("vendor/cache"),
+ :rubygems_version => "1.3.2"
simulate_new_machine
- lockfile <<-L
- GEM
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
- #{checksums}
- L
-
- 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("myrack-1.0.0")}")
-
- expect(cached_gem("myrack-1.0.0")).to exist
- cached_gem("myrack-1.0.0").rmtree
bundle :install
- expect(cached_gem("myrack-1.0.0")).to exist
- end
-
- it "installs a modified gem with a non-matching checksum when the API implementation does not provide checksums" do
- setup_main_repo
- cached_gem("myrack-1.0.0").rmtree
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
- simulate_new_machine
-
- lockfile <<-L
- GEM
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
- L
-
- bundle :install, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("rack-1.0.0")).to exist
end
it "handles directories and non .gem files in the cache" do
- setup_main_repo
bundled_app("vendor/cache/foo").mkdir
File.open(bundled_app("vendor/cache/bar"), "w") {|f| f.write("not a gem") }
bundle :cache
end
it "does not say that it is removing gems when it isn't actually doing so" do
- setup_main_repo
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "cache"
bundle "install"
@@ -396,10 +304,9 @@ RSpec.describe "bundle cache" do
end
it "does not warn about all if it doesn't have any git/path dependency" do
- setup_main_repo
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "cache"
expect(out).not_to match(/\-\-all/)
@@ -407,10 +314,10 @@ RSpec.describe "bundle cache" do
it "should install gems with the name bundler in them (that aren't bundler)" do
build_gem "foo-bundler", "1.0",
- path: bundled_app("vendor/cache")
+ :path => bundled_app("vendor/cache")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo-bundler"
G
diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb
index ea91829003..d2671b5f15 100644
--- a/spec/bundler/cache/git_spec.rb
+++ b/spec/bundler/cache/git_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe "bundle cache with git" do
ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -27,7 +27,6 @@ RSpec.describe "bundle cache with git" do
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist
expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.bundlecache")).to be_file
- expect(Dir.glob(bundled_app("vendor/cache/foo-1.0-#{ref}/hooks/*.sample"))).to be_empty
FileUtils.rm_rf lib_path("foo-1.0")
expect(the_bundle).to include_gems "foo 1.0"
@@ -38,7 +37,7 @@ RSpec.describe "bundle cache with git" do
ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -58,7 +57,7 @@ RSpec.describe "bundle cache with git" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -76,7 +75,7 @@ RSpec.describe "bundle cache with git" do
old_ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -90,7 +89,7 @@ RSpec.describe "bundle cache with git" do
ref = git.ref_for("main", 11)
expect(ref).not_to eq(old_ref)
- bundle "update", all: true
+ bundle "update", :all => true
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
@@ -106,7 +105,7 @@ RSpec.describe "bundle cache with git" do
old_ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -135,7 +134,7 @@ RSpec.describe "bundle cache with git" do
ref = git.ref_for("main", 11)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :main
G
@@ -155,92 +154,7 @@ RSpec.describe "bundle cache with git" do
expect(out).to eq("LOCAL")
end
- it "can use gems after copying install folder to a different machine with git not installed" do
- build_git "foo"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{lib_path("foo-1.0")}'
- G
- bundle "config set path vendor/bundle"
- bundle :install
-
- simulate_new_machine
- with_path_as "" do
- bundle "config set deployment true"
- bundle "install --local"
- expect(the_bundle).to include_gem "foo 1.0"
- end
- end
-
- it "can install after bundle cache without cloning remote repositories" do
- build_git "foo"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{lib_path("foo-1.0")}'
- G
- bundle "config set cache_all true"
- bundle :cache, "all-platforms" => true
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first.to_s
-
- simulate_new_machine
- bundle "config set frozen true"
- bundle "install --local --verbose"
- expect(out).to_not include("Fetching")
- expect(the_bundle).to include_gem "foo 1.0"
- end
-
- it "can install after bundle cache without cloning remote repositories even without the original cache" do
- build_git "foo"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{lib_path("foo-1.0")}'
- G
- bundle "config set cache_all true"
- bundle :cache, "all-platforms" => true
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first.to_s
-
- simulate_new_machine
- bundle "config set frozen true"
- FileUtils.rm_rf "#{default_bundle_path}/cache/bundler/git/foo-1.0-*"
- bundle "install --local --verbose"
- expect(out).to_not include("Fetching")
- expect(the_bundle).to include_gem "foo 1.0"
- end
-
- it "can install after bundle cache without cloning remote repositories with only git tracked files" do
- build_git "foo"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{lib_path("foo-1.0")}'
- G
- bundle "config set cache_all true"
- bundle :cache, "all-platforms" => true
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first.to_s
-
- simulate_new_machine
- bundle "config set frozen true"
- FileUtils.rm_rf "#{default_bundle_path}/cache/bundler/git/foo-1.0-*"
-
- # Remove untracked files (including the empty refs dir in the cache)
- Dir.chdir(bundled_app) do
- system(*%W[git init --quiet])
- system(*%W[git add --all])
- system(*%W[git clean -d --force --quiet])
- end
-
- bundle "install --local --verbose"
- expect(out).to_not include("Fetching")
- expect(the_bundle).to include_gem "foo 1.0"
- end
-
- it "copies repository to vendor cache" do
+ it "copies repository to vendor cache, including submodules" do
# CVE-2022-39253: https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/
system(*%W[git config --global protocol.file.allow always])
@@ -250,11 +164,11 @@ RSpec.describe "bundle cache with git" do
s.add_dependency "submodule"
end
- git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0")
- git "commit -m \"submodulator\"", lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("has_submodule-1.0")}", :submodules => true do
gem "has_submodule"
end
@@ -265,147 +179,45 @@ RSpec.describe "bundle cache with git" do
bundle :cache
expect(bundled_app("vendor/cache/has_submodule-1.0-#{ref}")).to exist
+ expect(bundled_app("vendor/cache/has_submodule-1.0-#{ref}/submodule-1.0")).to exist
expect(the_bundle).to include_gems "has_submodule 1.0"
end
- it "can install after bundle cache with git not installed" do
- build_git "foo"
+ it "caches pre-evaluated gemspecs" do
+ git = build_git "foo"
- gemfile <<-G
- source "https://gem.repo1"
+ # Insert a gemspec method that shells out
+ spec_lines = lib_path("foo-1.0/foo.gemspec").read.split("\n")
+ spec_lines.insert(-2, "s.description = `echo bob`")
+ update_git("foo") {|s| s.write "foo.gemspec", spec_lines.join("\n") }
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set path vendor/bundle"
bundle "config set cache_all true"
- bundle :cache, "all-platforms" => true, :install => false
-
- simulate_new_machine
- with_path_as "" do
- bundle "config set deployment true"
- bundle :install, local: true
- expect(the_bundle).to include_gem "foo 1.0"
- end
- end
-
- it "can install after bundle cache generated with an older Bundler that kept checkouts in the cache" do
- git = build_git("foo")
- locked_revision = git.ref_for("main")
- path_revision = git.ref_for("main", 11)
-
- git_path = lib_path("foo-1.0")
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{git_path}'
- G
- lockfile <<~L
- GIT
- remote: #{git_path}/
- revision: #{locked_revision}
- specs:
- foo (1.0)
-
- GEM
- remote: https://gem.repo1/
- specs:
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- # Simulate an old incorrect situation where vendor/cache would be the install location of git gems
- FileUtils.mkdir_p bundled_app("vendor/cache")
- FileUtils.cp_r git_path, bundled_app("vendor/cache/foo-1.0-#{path_revision}")
- FileUtils.rm_rf bundled_app("vendor/cache/foo-1.0-#{path_revision}/.git")
+ bundle :cache
- bundle :install, env: { "BUNDLE_DEPLOYMENT" => "true", "BUNDLE_CACHE_ALL" => "true" }
+ ref = git.ref_for("main", 11)
+ gemspec = bundled_app("vendor/cache/foo-1.0-#{ref}/foo.gemspec").read
+ expect(gemspec).to_not match("`echo bob`")
end
- it "respects the --no-install flag" do
- git = build_git "foo", &:add_c_extension
- ref = git.ref_for("main", 11)
+ it "can install after bundle cache with git not installed" do
+ build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
bundle "config set cache_all true"
+ bundle :cache, "all-platforms" => true, :install => false
- # The algorithm for the cache location for a git checkout is
- # in Bundle::Source::Git#cache_path
- cache_path_name = "foo-1.0-#{Digest(:SHA1).hexdigest(lib_path("foo-1.0").to_s)}"
-
- # Run this test twice. This is because materially different codepaths
- # will get hit the second time around.
- # The first time, Bundler::Sources::Git#install_path is set to the system
- # wide cache directory bundler/gems; the second time, it's set to the
- # vendor/cache directory. We don't want the native extension to appear in
- # either of these places, so run the `bundle cache` command twice.
- 2.times do
- bundle :cache, "all-platforms" => true, :install => false
-
- # it did _NOT_ actually install the gem - neither in $GEM_HOME (bundler 2 mode),
- # nor in .bundle (bundler 3 mode)
- expect(Pathname.new(File.join(default_bundle_path, "gems/foo-1.0-#{ref}"))).to_not exist
- # it _did_ cache the gem in vendor/
- expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
- # it did _NOT_ build the gems extensions in the vendor/ dir
- expect(Dir[bundled_app("vendor/cache/foo-1.0-#{ref}/lib/foo_c*")]).to be_empty
- # it _did_ cache the git checkout
- expect(default_cache_path("git", cache_path_name)).to exist
- # And the checkout is a bare checkout
- expect(default_cache_path("git", cache_path_name, "HEAD")).to exist
- end
-
- # Subsequently installing the gem should compile it.
- # _currently_, the gem gets compiled in vendor/cache, and vendor/cache is added
- # to the $LOAD_PATH for git extensions, so it all kind of "works". However, in the
- # future we would like to stop adding vendor/cache to the $LOAD_PATH for git extensions
- # and instead treat them identically to normal gems (where the gem install location,
- # not the cache location, is added to $LOAD_PATH).
- # Verify that the compilation worked and the result is in $LOAD_PATH by simply attempting
- # to require it; that should make sure this spec does not break if the load path behaviour
- # is changed.
- bundle :install, local: true
- ruby <<~R, raise_on_error: false
- require 'bundler/setup'
- require 'foo_c'
- R
- expect(last_command).to_not be_failure
- end
-
- it "doesn't fail when git gem has extensions and an empty cache folder is present before bundle install" do
- build_git "puma" do |s|
- s.add_dependency "rake"
- s.extensions << "Rakefile"
- s.executables = "puma"
- s.write "Rakefile", <<-RUBY
- task :default do
- path = File.expand_path("../lib", __FILE__)
- FileUtils.mkdir_p(path)
- File.open("\#{path}/puma.rb", "w") do |f|
- f.puts "PUMA = 'YES'"
- end
- end
- RUBY
+ simulate_new_machine
+ with_path_as "" do
+ bundle "config set deployment true"
+ bundle :install, :local => true
+ expect(the_bundle).to include_gem "foo 1.0"
end
-
- FileUtils.mkdir_p(bundled_app("vendor/cache"))
- bundle "config set cache_all all"
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "puma", :git => "#{lib_path("puma-1.0")}"
- G
-
- bundle "exec puma"
-
- expect(out).to eq("YES")
end
end
diff --git a/spec/bundler/cache/path_spec.rb b/spec/bundler/cache/path_spec.rb
index 966cb6f531..2ad136a008 100644
--- a/spec/bundler/cache/path_spec.rb
+++ b/spec/bundler/cache/path_spec.rb
@@ -2,10 +2,10 @@
RSpec.describe "bundle cache with path" do
it "is no-op when the path is within the bundle" do
- build_lib "foo", path: bundled_app("lib/foo")
+ build_lib "foo", :path => bundled_app("lib/foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{bundled_app("lib/foo")}'
G
@@ -19,7 +19,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -35,10 +35,10 @@ RSpec.describe "bundle cache with path" do
libname = File.basename(bundled_app) + "_gem"
libpath = File.join(File.dirname(bundled_app), libname)
- build_lib libname, path: libpath
+ build_lib libname, :path => libpath
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "#{libname}", :path => '#{libpath}'
G
@@ -54,7 +54,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -77,7 +77,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -89,7 +89,7 @@ RSpec.describe "bundle cache with path" do
build_lib "bar"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :path => '#{lib_path("bar-1.0")}'
G
@@ -97,11 +97,11 @@ RSpec.describe "bundle cache with path" do
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
end
- it "does not cache path gems by default", bundler: "< 3" do
+ it "does not cache path gems by default", :bundler => "< 3" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -110,11 +110,11 @@ RSpec.describe "bundle cache with path" do
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
end
- it "caches path gems by default", bundler: "3" do
+ it "caches path gems by default", :bundler => "3" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -127,7 +127,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -136,7 +136,7 @@ RSpec.describe "bundle cache with path" do
build_lib "bar"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
gem "bar", :path => '#{lib_path("bar-1.0")}'
G
@@ -149,7 +149,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -158,12 +158,12 @@ RSpec.describe "bundle cache with path" do
build_lib "baz"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
gem "baz", :path => '#{lib_path("baz-1.0")}'
G
- bundle "cache --no-all", raise_on_error: false
+ bundle "cache --no-all", :raise_on_error => false
expect(bundled_app("vendor/cache/baz-1.0")).not_to exist
end
end
diff --git a/spec/bundler/cache/platform_spec.rb b/spec/bundler/cache/platform_spec.rb
index 71c0eaee8e..128278956c 100644
--- a/spec/bundler/cache/platform_spec.rb
+++ b/spec/bundler/cache/platform_spec.rb
@@ -3,10 +3,10 @@
RSpec.describe "bundle cache with multiple platforms" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
platforms :mri, :rbx do
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
end
platforms :jruby do
@@ -16,9 +16,9 @@ RSpec.describe "bundle cache with multiple platforms" do
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
activesupport (2.3.5)
PLATFORMS
@@ -26,24 +26,24 @@ RSpec.describe "bundle cache with multiple platforms" do
java
DEPENDENCIES
- myrack (1.0.0)
+ rack (1.0.0)
activesupport (2.3.5)
G
- cache_gems "myrack-1.0.0", "activesupport-2.3.5"
+ cache_gems "rack-1.0.0", "activesupport-2.3.5"
end
it "ensures that a successful bundle install does not delete gems for other platforms" do
bundle "install"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist
end
it "ensures that a successful bundle update does not delete gems for other platforms" do
- bundle "update", all: true
+ bundle "update", :all => true
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist
end
end
diff --git a/spec/bundler/commands/add_spec.rb b/spec/bundler/commands/add_spec.rb
index 0a0d4c0046..5a5b534e8d 100644
--- a/spec/bundler/commands/add_spec.rb
+++ b/spec/bundler/commands/add_spec.rb
@@ -9,34 +9,24 @@ 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"
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling", "~> 0.0.1"
G
end
context "when no gems are specified" do
it "shows error" do
- bundle "add", raise_on_error: false
+ bundle "add", :raise_on_error => false
expect(err).to include("Please specify gems to add")
end
end
- context "when Gemfile is empty, and frozen mode is set" do
- it "shows error" do
- gemfile 'source "https://gem.repo2"'
- bundle "add bar", raise_on_error: false, env: { "BUNDLE_FROZEN" => "true" }
-
- expect(err).to include("Frozen mode is set, but there's no lockfile")
- end
- end
-
describe "without version specified" do
it "version requirement becomes ~> major.minor.patch when resolved version is < 1.0" do
bundle "add 'bar'"
@@ -61,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
@@ -80,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
@@ -113,9 +96,9 @@ RSpec.describe "bundle add" do
describe "with --source" do
it "adds dependency with specified source" do
- bundle "add 'foo' --source='https://gem.repo2'"
+ bundle "add 'foo' --source='#{file_uri_for(gem_repo2)}'"
- expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :source => "https://gem.repo2"})
+ expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :source => "#{file_uri_for(gem_repo2)}"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -140,7 +123,7 @@ RSpec.describe "bundle add" do
describe "with --git and --branch" do
before do
- update_git "foo", "2.0", branch: "test"
+ update_git "foo", "2.0", :branch => "test"
end
it "adds dependency with specified git source and branch" do
@@ -161,81 +144,26 @@ RSpec.describe "bundle add" do
end
describe "with --github" do
- it "adds dependency with specified github source" 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
describe "with --github and --branch" do
- it "adds dependency with specified github source and branch" 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
describe "with --github and --ref" do
- it "adds dependency with specified github source and ref" 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"})
- end
- end
-
- describe "with --git and --glob" do
- it "adds dependency with specified git source" do
- bundle "add foo --git=#{lib_path("foo-2.0")} --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :glob => "\./\*\.gemspec"})
- expect(the_bundle).to include_gems "foo 2.0"
- end
- end
-
- describe "with --git and --branch and --glob" do
- before do
- update_git "foo", "2.0", branch: "test"
- end
-
- it "adds dependency with specified git source and branch" do
- bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :branch => "test", :glob => "\./\*\.gemspec"})
- expect(the_bundle).to include_gems "foo 2.0"
- end
- end
-
- describe "with --git and --ref and --glob" do
- it "adds dependency with specified git source and branch" do
- bundle "add foo --git=#{lib_path("foo-2.0")} --ref=#{revision_for(lib_path("foo-2.0"))} --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2\.0", :git => "#{lib_path("foo-2.0")}", :ref => "#{revision_for(lib_path("foo-2.0"))}", :glob => "\./\*\.gemspec"})
- expect(the_bundle).to include_gems "foo 2.0"
- end
- end
-
- describe "with --github and --glob" do
- it "adds dependency with specified github source" do
- bundle "add rake --github=ruby/rake --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :glob => "\.\/\*\.gemspec"})
- end
- end
-
- describe "with --github and --branch --and glob" do
- it "adds dependency with specified github source and branch" do
- bundle "add rake --github=ruby/rake --branch=master --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :branch => "master", :glob => "\.\/\*\.gemspec"})
- end
- end
-
- describe "with --github and --ref and --glob" do
- it "adds dependency with specified github source and ref" do
- bundle "add rake --github=ruby/rake --ref=5c60da8 --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :ref => "5c60da8", :glob => "\.\/\*\.gemspec"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake", :ref => "5c60da8"})
end
end
@@ -249,30 +177,30 @@ RSpec.describe "bundle add" do
end
it "using combination of short form options works like long form" do
- bundle "add 'foo' -s='https://gem.repo2' -g='development' -v='~>1.0'"
- expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 1.0", :group => :development, :source => "https://gem.repo2")
+ bundle "add 'foo' -s='#{file_uri_for(gem_repo2)}' -g='development' -v='~>1.0'"
+ expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 1.0", :group => :development, :source => "#{file_uri_for(gem_repo2)}")
expect(the_bundle).to include_gems "foo 1.1"
end
it "shows error message when version is not formatted correctly" do
- bundle "add 'foo' -v='~>1 . 0'", raise_on_error: false
+ bundle "add 'foo' -v='~>1 . 0'", :raise_on_error => false
expect(err).to match("Invalid gem requirement pattern '~>1 . 0'")
end
it "shows error message when gem cannot be found" do
bundle "config set force_ruby_platform true"
- bundle "add 'werk_it'", raise_on_error: false
+ bundle "add 'werk_it'", :raise_on_error => false
expect(err).to match("Could not find gem 'werk_it' in")
- bundle "add 'werk_it' -s='https://gem.repo2'", raise_on_error: false
+ bundle "add 'werk_it' -s='#{file_uri_for(gem_repo2)}'", :raise_on_error => false
expect(err).to match("Could not find gem 'werk_it' in rubygems repository")
end
it "shows error message when source cannot be reached" do
- bundle "add 'baz' --source='http://badhostasdf'", raise_on_error: false, artifice: "fail"
+ bundle "add 'baz' --source='http://badhostasdf'", :raise_on_error => false
expect(err).to include("Could not reach host badhostasdf. Check your network connection and try again.")
- bundle "add 'baz' --source='file://does/not/exist'", raise_on_error: false
+ bundle "add 'baz' --source='file://does/not/exist'", :raise_on_error => false
expect(err).to include("Could not fetch specs from file://does/not/exist/")
end
@@ -302,9 +230,9 @@ RSpec.describe "bundle add" do
describe "with --optimistic and --strict" do
it "throws error" do
- bundle "add 'foo' --strict --optimistic", raise_on_error: false
+ bundle "add 'foo' --strict --optimistic", :raise_on_error => false
- expect(err).to include("You cannot specify `--strict` and `--optimistic` at the same time")
+ expect(err).to include("You can not specify `--strict` and `--optimistic` at the same time")
end
end
@@ -317,7 +245,7 @@ RSpec.describe "bundle add" do
end
it "throws error if any of the specified gems are present in the gemfile with different version" do
- bundle "add weakling bar", raise_on_error: false
+ bundle "add weakling bar", :raise_on_error => false
expect(err).to include("You cannot specify the same gem twice with different version requirements")
expect(err).to include("You specified: weakling (~> 0.0.1) and weakling (>= 0).")
@@ -327,41 +255,41 @@ RSpec.describe "bundle add" do
describe "when a gem is added which is already specified in Gemfile with version" do
it "shows an error when added with different version requirement" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "1.0"
G
- bundle "add 'myrack' --version=1.1", raise_on_error: false
+ bundle "add 'rack' --version=1.1", :raise_on_error => false
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).to include("If you want to update the gem version, run `bundle update myrack`. You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
+ expect(err).to include("If you want to update the gem version, run `bundle update rack`. You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
end
it "shows error when added without version requirements" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "1.0"
G
- bundle "add 'myrack'", raise_on_error: false
+ bundle "add 'rack'", :raise_on_error => false
expect(err).to include("Gem already added.")
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).not_to include("If you want to update the gem version, run `bundle update myrack`. You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
+ expect(err).not_to include("If you want to update the gem version, run `bundle update rack`. You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
end
end
describe "when a gem is added which is already specified in Gemfile without version" do
it "shows an error when added with different version requirement" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
- bundle "add 'myrack' --version=1.1", raise_on_error: false
+ bundle "add 'rack' --version=1.1", :raise_on_error => false
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).to include("If you want to update the gem version, run `bundle update myrack`.")
+ expect(err).to include("If you want to update the gem version, run `bundle update rack`.")
expect(err).not_to include("You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
end
end
@@ -370,8 +298,8 @@ RSpec.describe "bundle add" do
it "caches all new dependencies added for the specified gem" do
bundle :cache
- bundle "add 'myrack' --version=1.0.0"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ bundle "add 'rack' --version=1.0.0"
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
end
end
diff --git a/spec/bundler/commands/binstubs_spec.rb b/spec/bundler/commands/binstubs_spec.rb
index 87a68a9cf1..72f4cc8e55 100644
--- a/spec/bundler/commands/binstubs_spec.rb
+++ b/spec/bundler/commands/binstubs_spec.rb
@@ -4,48 +4,48 @@ RSpec.describe "bundle binstubs <gem>" do
context "when the gem exists in the lockfile" do
it "sets up the binstub" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack"
+ bundle "binstubs rack"
- expect(bundled_app("bin/myrackup")).to exist
+ expect(bundled_app("bin/rackup")).to exist
end
it "does not install other binstubs" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "rails"
G
bundle "binstubs rails"
- expect(bundled_app("bin/myrackup")).not_to exist
+ expect(bundled_app("bin/rackup")).not_to exist
expect(bundled_app("bin/rails")).to exist
end
it "does install multiple binstubs" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "rails"
G
- bundle "binstubs rails myrack"
+ bundle "binstubs rails rack"
- expect(bundled_app("bin/myrackup")).to exist
+ expect(bundled_app("bin/rackup")).to exist
expect(bundled_app("bin/rails")).to exist
end
it "allows installing all binstubs" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle :binstubs, all: true
+ bundle :binstubs, :all => true
expect(bundled_app("bin/rails")).to exist
expect(bundled_app("bin/rake")).to exist
@@ -53,34 +53,34 @@ RSpec.describe "bundle binstubs <gem>" do
it "allows installing binstubs for all platforms" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack --all-platforms"
+ bundle "binstubs rack --all-platforms"
- expect(bundled_app("bin/myrackup")).to exist
- expect(bundled_app("bin/myrackup.cmd")).to exist
+ expect(bundled_app("bin/rackup")).to exist
+ expect(bundled_app("bin/rackup.cmd")).to exist
end
it "displays an error when used without any gem" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs", raise_on_error: false
+ bundle "binstubs", :raise_on_error => false
expect(exitstatus).to eq(1)
expect(err).to include("`bundle binstubs` needs at least one gem to run.")
end
it "displays an error when used with --all and gems" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack", all: true, raise_on_error: false
+ bundle "binstubs rack", :all => true, :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("Cannot specify --all with specific gems")
end
@@ -88,17 +88,17 @@ RSpec.describe "bundle binstubs <gem>" do
context "when generating bundle binstub outside bundler" do
it "should abort" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack"
+ bundle "binstubs rack"
File.open(bundled_app("bin/bundle"), "wb") do |file|
file.print "OMG"
end
- sys_exec "bin/myrackup", raise_on_error: false
+ sys_exec "bin/rackup", :raise_on_error => false
expect(err).to include("was not generated by Bundler")
end
@@ -108,42 +108,37 @@ RSpec.describe "bundle binstubs <gem>" do
before do
pristine_system_gems "bundler-#{system_bundler_version}"
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "prints_loaded_gems", "1.0" do |s|
s.executables = "print_loaded_gems"
s.bindir = "exe"
- s.write "exe/print_loaded_gems", <<~R
- #!/usr/bin/env ruby
+ s.write "exe/print_loaded_gems", <<-R
specs = Gem.loaded_specs.values.reject {|s| s.default_gem? }
puts specs.map(&:full_name).sort.inspect
R
end
-
- build_bundler locked_bundler_version
end
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "prints_loaded_gems"
G
- bundle "binstubs bundler myrack prints_loaded_gems"
+ bundle "binstubs bundler rack prints_loaded_gems"
end
let(:system_bundler_version) { Bundler::VERSION }
- let(:locked_bundler_version) { nil }
- let(:lockfile_content) { lockfile.gsub(system_bundler_version, locked_bundler_version) }
it "runs bundler" do
- bundle "install --verbose", bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "DEBUG" => "1" }
expect(out).to include %(Using bundler #{system_bundler_version}\n)
end
context "when BUNDLER_VERSION is set" do
it "runs the correct version of bundler" do
- bundle "install", env: { "BUNDLER_VERSION" => "999.999.999" }, raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "BUNDLER_VERSION" => "999.999.999" }, :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (999.999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '999.999.999'`")
@@ -152,36 +147,19 @@ RSpec.describe "bundle binstubs <gem>" do
it "runs the correct version of bundler even if a higher version is installed" do
system_gems "bundler-999.999.998", "bundler-999.999.999"
- bundle "install --verbose", env: { "BUNDLER_VERSION" => "999.999.998" }, raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "BUNDLER_VERSION" => "999.999.998", "DEBUG" => "1" }, :raise_on_error => false
expect(out).to include %(Using bundler 999.999.998\n)
end
end
context "when a lockfile exists with a locked bundler version" do
- let(:locked_bundler_version) { "999.999" }
-
context "and the version is newer" do
before do
- lockfile lockfile_content
+ lockfile lockfile.gsub(system_bundler_version, "999.999")
end
it "runs the correct version of bundler" do
- bundle "install", raise_on_error: false, bundle_bin: "bin/bundle"
- expect(exitstatus).to eq(42)
- expect(err).to include("Activating bundler (~> 999.999) failed:").
- and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
- end
- end
-
- context "and the version is newer when given `gems.rb` and `gems.locked`" do
- before do
- gemfile bundled_app("gems.rb"), gemfile
- lockfile bundled_app("gems.locked"), lockfile_content
- end
-
- it "runs the correct version of bundler" do
- bundle "install", env: { "BUNDLE_GEMFILE" => "gems.rb" }, raise_on_error: false, bundle_bin: "bin/bundle"
-
+ sys_exec "bin/bundle install", :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
@@ -190,31 +168,13 @@ RSpec.describe "bundle binstubs <gem>" do
context "and the version is older and a different major" do
let(:system_bundler_version) { "55" }
- let(:locked_bundler_version) { "44" }
before do
- lockfile lockfile_content
+ lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 44.0")
end
it "runs the correct version of bundler" do
- bundle "install", raise_on_error: false, bundle_bin: "bin/bundle"
- expect(exitstatus).to eq(42)
- expect(err).to include("Activating bundler (~> 44.0) failed:").
- and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 44.0'`")
- end
- end
-
- context "and the version is older and a different major when given `gems.rb` and `gems.locked`" do
- let(:system_bundler_version) { "55" }
- let(:locked_bundler_version) { "44" }
-
- before do
- gemfile bundled_app("gems.rb"), gemfile
- lockfile bundled_app("gems.locked"), lockfile_content
- end
-
- it "runs the correct version of bundler" do
- bundle "install", env: { "BUNDLE_GEMFILE" => "gems.rb" }, raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 44.0) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 44.0'`")
@@ -223,22 +183,21 @@ RSpec.describe "bundle binstubs <gem>" do
context "and the version is older and the same major" do
let(:system_bundler_version) { "2.999.999" }
- let(:locked_bundler_version) { "2.3.0" }
before do
- lockfile lockfile_content
+ lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 2.3.0")
end
- it "installs and runs the exact version of bundler", rubygems: ">= 3.3.0.dev" do
- bundle "install --verbose", bundle_bin: "bin/bundle"
+ it "installs and runs the exact version of bundler", :rubygems => ">= 3.3.0.dev", :realworld => true do
+ sys_exec "bin/bundle install --verbose", :artifice => "vcr"
expect(exitstatus).not_to eq(42)
expect(out).to include("Bundler 2.999.999 is running, but your lockfile was generated with 2.3.0. Installing Bundler 2.3.0 and restarting using that version.")
expect(out).to include("Using bundler 2.3.0")
expect(err).not_to include("Activating bundler (~> 2.3.0) failed:")
end
- it "runs the available version of bundler", rubygems: "< 3.3.0.dev" do
- bundle "install --verbose", bundle_bin: "bin/bundle"
+ it "runs the available version of bundler", :rubygems => "< 3.3.0.dev" do
+ sys_exec "bin/bundle install --verbose"
expect(exitstatus).not_to eq(42)
expect(out).not_to include("Bundler 2.999.999 is running, but your lockfile was generated with 2.3.0. Installing Bundler 2.3.0 and restarting using that version.")
expect(out).to include("Using bundler 2.999.999")
@@ -248,14 +207,13 @@ RSpec.describe "bundle binstubs <gem>" do
context "and the version is a pre-releaser" do
let(:system_bundler_version) { "55" }
- let(:locked_bundler_version) { "2.12.0.a" }
before do
- lockfile lockfile_content
+ lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 2.12.0.a")
end
it "runs the correct version of bundler when the version is a pre-release" do
- bundle "install", raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 2.12.a) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 2.12.a'`")
@@ -264,8 +222,10 @@ RSpec.describe "bundle binstubs <gem>" do
end
context "when update --bundler is called" do
- it "calls through to the latest bundler version" do
- bundle "update --bundler --verbose", bundle_bin: "bin/bundle"
+ before { lockfile.gsub(system_bundler_version, "1.1.1") }
+
+ it "calls through to the latest bundler version", :realworld do
+ sys_exec "bin/bundle update --bundler", :env => { "DEBUG" => "1" }
using_bundler_line = /Using bundler ([\w\.]+)\n/.match(out)
expect(using_bundler_line).to_not be_nil
latest_version = using_bundler_line[1]
@@ -273,7 +233,7 @@ RSpec.describe "bundle binstubs <gem>" do
end
it "calls through to the explicit bundler version" do
- bundle "update --bundler=999.999.999", raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle update --bundler=999.999.999", :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (999.999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '999.999.999'`")
@@ -283,7 +243,7 @@ RSpec.describe "bundle binstubs <gem>" do
context "without a lockfile" do
it "falls back to the latest installed bundler" do
FileUtils.rm bundled_app_lock
- bundle "install --verbose", bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "DEBUG" => "1" }
expect(out).to include "Using bundler #{system_bundler_version}\n"
end
end
@@ -291,14 +251,14 @@ RSpec.describe "bundle binstubs <gem>" do
context "using another binstub" do
it "loads all gems" do
sys_exec bundled_app("bin/print_loaded_gems").to_s
- expect(out).to eq %(["bundler-#{Bundler::VERSION}", "myrack-1.2", "prints_loaded_gems-1.0"])
+ expect(out).to eq %(["bundler-#{Bundler::VERSION}", "prints_loaded_gems-1.0", "rack-1.2"])
end
context "when requesting a different bundler version" do
before { lockfile lockfile.gsub(Bundler::VERSION, "999.999.999") }
it "attempts to load that version" do
- sys_exec bundled_app("bin/myrackup").to_s, raise_on_error: false
+ sys_exec bundled_app("bin/rackup").to_s, :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
@@ -310,11 +270,11 @@ RSpec.describe "bundle binstubs <gem>" do
it "installs binstubs from git gems" do
FileUtils.mkdir_p(lib_path("foo/bin"))
FileUtils.touch(lib_path("foo/bin/foo"))
- build_git "foo", "1.0", path: lib_path("foo") do |s|
+ build_git "foo", "1.0", :path => lib_path("foo") do |s|
s.executables = %w[foo]
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo")}"
G
@@ -326,11 +286,11 @@ RSpec.describe "bundle binstubs <gem>" do
it "installs binstubs from path gems" do
FileUtils.mkdir_p(lib_path("foo/bin"))
FileUtils.touch(lib_path("foo/bin/foo"))
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.executables = %w[foo]
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
@@ -342,12 +302,12 @@ RSpec.describe "bundle binstubs <gem>" do
it "sets correct permissions for binstubs" do
with_umask(0o002) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack"
- binary = bundled_app("bin/myrackup")
+ bundle "binstubs rack"
+ binary = bundled_app("bin/rackup")
expect(File.stat(binary).mode.to_s(8)).to eq(Gem.win_platform? ? "100644" : "100775")
end
end
@@ -355,12 +315,12 @@ RSpec.describe "bundle binstubs <gem>" do
context "when using --shebang" do
it "sets the specified shebang for the binstub" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack --shebang jruby"
- expect(File.readlines(bundled_app("bin/myrackup")).first).to eq("#!/usr/bin/env jruby\n")
+ bundle "binstubs rack --shebang jruby"
+ expect(File.readlines(bundled_app("bin/rackup")).first).to eq("#!/usr/bin/env jruby\n")
end
end
end
@@ -368,10 +328,10 @@ RSpec.describe "bundle binstubs <gem>" do
context "when the gem doesn't exist" do
it "displays an error with correct status" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- bundle "binstubs doesnt_exist", raise_on_error: false
+ bundle "binstubs doesnt_exist", :raise_on_error => false
expect(exitstatus).to eq(7)
expect(err).to include("Could not find gem 'doesnt_exist'.")
@@ -381,23 +341,23 @@ RSpec.describe "bundle binstubs <gem>" do
context "--path" do
it "sets the binstubs dir" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack --path exec"
+ bundle "binstubs rack --path exec"
- expect(bundled_app("exec/myrackup")).to exist
+ expect(bundled_app("exec/rackup")).to exist
end
- it "setting is saved for bundle install", bundler: "< 3" do
+ it "setting is saved for bundle install", :bundler => "< 3" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "rails"
G
- bundle "binstubs myrack", path: "exec"
+ bundle "binstubs rack", :path => "exec"
bundle :install
expect(bundled_app("exec/rails")).to exist
@@ -407,34 +367,34 @@ RSpec.describe "bundle binstubs <gem>" do
context "with --standalone option" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "rails"
G
end
it "generates a standalone binstub" do
- bundle "binstubs myrack --standalone"
- expect(bundled_app("bin/myrackup")).to exist
+ bundle "binstubs rack --standalone"
+ expect(bundled_app("bin/rackup")).to exist
end
it "generates a binstub that does not depend on rubygems or bundler" do
- bundle "binstubs myrack --standalone"
- expect(File.read(bundled_app("bin/myrackup"))).to_not include("Gem.bin_path")
+ bundle "binstubs rack --standalone"
+ expect(File.read(bundled_app("bin/rackup"))).to_not include("Gem.bin_path")
end
context "when specified --path option" do
it "generates a standalone binstub at the given path" do
- bundle "binstubs myrack --standalone --path foo"
- expect(bundled_app("foo/myrackup")).to exist
+ bundle "binstubs rack --standalone --path foo"
+ expect(bundled_app("foo/rackup")).to exist
end
end
context "when specified --all-platforms option" do
it "generates standalone binstubs for all platforms" do
- bundle "binstubs myrack --standalone --all-platforms"
- expect(bundled_app("bin/myrackup")).to exist
- expect(bundled_app("bin/myrackup.cmd")).to exist
+ bundle "binstubs rack --standalone --all-platforms"
+ expect(bundled_app("bin/rackup")).to exist
+ expect(bundled_app("bin/rackup.cmd")).to exist
end
end
@@ -450,7 +410,7 @@ RSpec.describe "bundle binstubs <gem>" do
context "when specified --all option" do
it "generates standalone binstubs for all gems except bundler" do
bundle "binstubs --standalone --all"
- expect(bundled_app("bin/myrackup")).to exist
+ expect(bundled_app("bin/rackup")).to exist
expect(bundled_app("bin/rails")).to exist
expect(bundled_app("bin/bundle")).not_to exist
expect(bundled_app("bin/bundler")).not_to exist
@@ -462,39 +422,39 @@ RSpec.describe "bundle binstubs <gem>" do
context "when the bin already exists" do
it "doesn't overwrite and warns" do
FileUtils.mkdir_p(bundled_app("bin"))
- File.open(bundled_app("bin/myrackup"), "wb") do |file|
+ File.open(bundled_app("bin/rackup"), "wb") do |file|
file.print "OMG"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack"
+ bundle "binstubs rack"
- expect(bundled_app("bin/myrackup")).to exist
- expect(File.read(bundled_app("bin/myrackup"))).to eq("OMG")
- expect(err).to include("Skipped myrackup")
+ expect(bundled_app("bin/rackup")).to exist
+ expect(File.read(bundled_app("bin/rackup"))).to eq("OMG")
+ expect(err).to include("Skipped rackup")
expect(err).to include("overwrite skipped stubs, use --force")
end
context "when using --force" do
it "overwrites the binstub" do
FileUtils.mkdir_p(bundled_app("bin"))
- File.open(bundled_app("bin/myrackup"), "wb") do |file|
+ File.open(bundled_app("bin/rackup"), "wb") do |file|
file.print "OMG"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack --force"
+ bundle "binstubs rack --force"
- expect(bundled_app("bin/myrackup")).to exist
- expect(File.read(bundled_app("bin/myrackup"))).not_to eq("OMG")
+ expect(bundled_app("bin/rackup")).to exist
+ expect(File.read(bundled_app("bin/rackup"))).not_to eq("OMG")
end
end
end
@@ -502,18 +462,18 @@ RSpec.describe "bundle binstubs <gem>" do
context "when the gem has no bins" do
it "suggests child gems if they have bins" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack-obama"
G
- bundle "binstubs myrack-obama"
- expect(err).to include("myrack-obama has no executables")
- expect(err).to include("myrack has: myrackup")
+ bundle "binstubs rack-obama"
+ expect(err).to include("rack-obama has no executables")
+ expect(err).to include("rack has: rackup")
end
it "works if child gems don't have bins" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "actionpack"
G
@@ -529,7 +489,7 @@ RSpec.describe "bundle binstubs <gem>" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "with_development_dependency"
G
@@ -541,25 +501,25 @@ RSpec.describe "bundle binstubs <gem>" do
context "when BUNDLE_INSTALL is specified" do
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set auto_install 1"
- bundle "binstubs myrack"
- expect(out).to include("Installing myrack 1.0.0")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle "binstubs rack"
+ expect(out).to include("Installing rack 1.0.0")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does nothing when already up to date" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set auto_install 1"
- bundle "binstubs myrack", env: { "BUNDLE_INSTALL" => "1" }
- expect(out).not_to include("Installing myrack 1.0.0")
+ bundle "binstubs rack", :env => { "BUNDLE_INSTALL" => "1" }
+ expect(out).not_to include("Installing rack 1.0.0")
end
end
end
diff --git a/spec/bundler/commands/cache_spec.rb b/spec/bundler/commands/cache_spec.rb
index ab8eb06838..356a658e7c 100644
--- a/spec/bundler/commands/cache_spec.rb
+++ b/spec/bundler/commands/cache_spec.rb
@@ -3,8 +3,8 @@
RSpec.describe "bundle cache" do
it "doesn't update the cache multiple times, even if it already exists" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :cache
@@ -17,14 +17,14 @@ RSpec.describe "bundle cache" do
context "with --gemfile" do
it "finds the gemfile" do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
bundle "cache --gemfile=NotGemfile"
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -32,15 +32,15 @@ RSpec.describe "bundle cache" do
context "without a gemspec" do
it "caches all dependencies except bundler itself" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gem 'bundler'
D
bundle "config set cache_all true"
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/bundler-0.9.gem")).to_not exist
end
end
@@ -63,15 +63,15 @@ RSpec.describe "bundle cache" do
it "caches all dependencies except bundler and the gemspec specified gem" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gemspec
D
bundle "config set cache_all true"
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/nokogiri-1.4.2.gem")).to exist
expect(bundled_app("vendor/cache/mygem-0.1.1.gem")).to_not exist
expect(bundled_app("vendor/cache/bundler-0.9.gem")).to_not exist
@@ -95,15 +95,15 @@ RSpec.describe "bundle cache" do
it "caches all dependencies except bundler and the gemspec specified gem" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gemspec
D
bundle "config set cache_all true"
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/nokogiri-1.4.2.gem")).to exist
expect(bundled_app("vendor/cache/mygem-0.1.1.gem")).to_not exist
expect(bundled_app("vendor/cache/bundler-0.9.gem")).to_not exist
@@ -139,8 +139,8 @@ RSpec.describe "bundle cache" do
it "caches all dependencies except bundler and the gemspec specified gems" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gemspec :name => 'mygem'
gemspec :name => 'mygem_test'
D
@@ -148,7 +148,7 @@ RSpec.describe "bundle cache" do
bundle "config set cache_all true"
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/nokogiri-1.4.2.gem")).to exist
expect(bundled_app("vendor/cache/weakling-0.0.3.gem")).to exist
expect(bundled_app("vendor/cache/mygem-0.1.1.gem")).to_not exist
@@ -158,16 +158,16 @@ RSpec.describe "bundle cache" do
end
end
- context "with --path", bundler: "< 3" do
+ context "with --path", :bundler => "< 3" do
it "sets root directory for gems" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
D
bundle "cache --path #{bundled_app("test")}"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(bundled_app("test/vendor/cache/")).to exist
end
end
@@ -175,60 +175,50 @@ RSpec.describe "bundle cache" do
context "with --no-install" do
it "puts the gems in vendor/cache but does not install them" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
D
bundle "cache --no-install"
- expect(the_bundle).not_to include_gems "myrack 1.0.0"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(the_bundle).not_to include_gems "rack 1.0.0"
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "does not prevent installing gems with bundle install" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
D
bundle "cache --no-install"
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not prevent installing gems with bundle update" do
gemfile <<-D
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
D
bundle "cache --no-install"
bundle "update --all"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
context "with --all-platforms" do
- it "puts the gems in vendor/cache even for other rubies", bundler: ">= 2.4.0" do
+ it "puts the gems in vendor/cache even for other rubies" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack', :platforms => [:ruby_20, :windows_20]
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', :platforms => [:ruby_20, :x64_mingw_20]
D
bundle "cache --all-platforms"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- end
-
- it "puts the gems in vendor/cache even for legacy windows rubies", bundler: ">= 2.4.0" do
- gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack', :platforms => [:ruby_20, :x64_mingw_20]
- D
-
- bundle "cache --all-platforms"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "does not attempt to install gems in without groups" do
@@ -241,39 +231,39 @@ RSpec.describe "bundle cache" do
end
bundle "config set --local without wo"
- install_gemfile <<-G, artifice: "compact_index_extra_api"
- source "https://main.repo"
- gem "myrack"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :wo do
gem "weakling"
- gem "uninstallable", :source => "https://main.repo/extra"
+ gem "uninstallable", :source => "#{file_uri_for(gem_repo4)}"
end
G
- bundle :cache, "all-platforms" => true, artifice: "compact_index_extra_api"
+ bundle :cache, "all-platforms" => true
expect(bundled_app("vendor/cache/weakling-0.0.3.gem")).to exist
expect(bundled_app("vendor/cache/uninstallable-2.0.gem")).to exist
- expect(the_bundle).to include_gem "myrack 1.0"
+ expect(the_bundle).to include_gem "rack 1.0"
expect(the_bundle).not_to include_gems "weakling", "uninstallable"
bundle "config set --local without wo"
- bundle :install, artifice: "compact_index_extra_api"
- expect(the_bundle).to include_gem "myrack 1.0"
- expect(the_bundle).not_to include_gems "weakling"
+ bundle :install
+ expect(the_bundle).to include_gem "rack 1.0"
+ expect(the_bundle).not_to include_gems "weakling", "uninstallable"
end
it "does not fail to cache gems in excluded groups when there's a lockfile but gems not previously installed" do
bundle "config set --local without wo"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "https://my.gem.repo.1"
+ gem "rack"
group :wo do
gem "weakling"
end
G
- bundle :lock
- bundle :cache, "all-platforms" => true
+ bundle :lock, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ bundle :cache, "all-platforms" => true, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
expect(bundled_app("vendor/cache/weakling-0.0.3.gem")).to exist
end
end
@@ -281,29 +271,29 @@ RSpec.describe "bundle cache" do
context "with frozen configured" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "install"
end
subject do
bundle "config set --local frozen true"
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
end
it "tries to install with frozen" do
bundle "config set deployment true"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
subject
expect(exitstatus).to eq(16)
- expect(err).to include("frozen mode")
+ expect(err).to include("deployment mode")
expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
+ expect(err).to include("* rack-obama")
bundle "env"
expect(out).to include("frozen").or include("deployment")
end
@@ -315,12 +305,12 @@ RSpec.describe "bundle cache" do
build_gem "racc", "2.0" do |s|
s.add_dependency "rake"
s.extensions << "Rakefile"
- s.write "Rakefile", "task(:default) { puts 'INSTALLING myrack' }"
+ s.write "Rakefile", "task(:default) { puts 'INSTALLING rack' }"
end
end
gemfile <<~G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "racc"
G
@@ -339,8 +329,8 @@ RSpec.describe "bundle install with gem sources" do
it "does not hit the remote at all" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
bundle :cache
@@ -348,14 +338,14 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.rm_rf gem_repo2
bundle "install --local"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not hit the remote at all in frozen mode" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
bundle :cache
@@ -365,14 +355,14 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not hit the remote at all when cache_all_platforms configured" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
bundle :cache
@@ -383,89 +373,29 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local path vendor/bundle"
bundle "install --local"
expect(out).not_to include("Fetching gem metadata")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "uses cached gems for secondary sources when cache_all_platforms configured" do
- build_repo4 do
- build_gem "foo", "1.0.0" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "foo", "1.0.0" do |s|
- s.platform = "arm64-darwin"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- source "https://gem.repo4" do
- gem "foo"
- end
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- specs:
-
- GEM
- remote: https://gem.repo4/
- specs:
- foo (1.0.0-x86_64-linux)
- foo (1.0.0-arm64-darwin)
-
- PLATFORMS
- arm64-darwin
- ruby
- x86_64-linux
-
- DEPENDENCIES
- foo
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- simulate_platform "x86_64-linux" do
- bundle "config set cache_all_platforms true"
- bundle "config set path vendor/bundle"
- bundle :cache, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
-
- build_repo4 do
- # simulate removal of all remote gems
- end
-
- # delete compact index cache
- FileUtils.rm_rf home(".bundle/cache/compact_index")
-
- bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
-
- expect(the_bundle).to include_gems "foo 1.0.0 x86_64-linux"
- end
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not reinstall already-installed gems" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :cache
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache") do |s|
- s.write "lib/myrack.rb", "raise 'omg'"
+ build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s|
+ s.write "lib/rack.rb", "raise 'omg'"
end
bundle :install
expect(err).to be_empty
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
it "ignores cached gems for the wrong platform" do
simulate_platform "java" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
bundle :cache
@@ -476,16 +406,17 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local force_ruby_platform true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
- expect(the_bundle).to include_gems("platform_specific 1.0 ruby")
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0.0 RUBY")
end
it "does not update the cache if --no-cache is passed" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundled_app("vendor/cache").mkpath
expect(bundled_app("vendor/cache").children).to be_empty
diff --git a/spec/bundler/commands/check_spec.rb b/spec/bundler/commands/check_spec.rb
index 18c4b2d89f..b4996977c1 100644
--- a/spec/bundler/commands/check_spec.rb
+++ b/spec/bundler/commands/check_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle check" do
it "returns success when the Gemfile is satisfied" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
@@ -13,17 +13,17 @@ RSpec.describe "bundle check" do
it "works with the --gemfile flag when not in the directory" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle "check --gemfile bundled_app/Gemfile", dir: tmp
+ bundle "check --gemfile bundled_app/Gemfile", :dir => tmp
expect(out).to include("The Gemfile's dependencies are satisfied")
end
it "creates a Gemfile.lock by default if one does not exist" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
@@ -36,7 +36,7 @@ RSpec.describe "bundle check" do
it "does not create a Gemfile.lock if --dry-run was passed" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
@@ -51,36 +51,25 @@ RSpec.describe "bundle check" do
system_gems ["rails-2.3.2"]
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
it "prints a generic error if a Gemfile.lock does not exist and a toplevel dependency does not exist" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(exitstatus).to be > 0
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
- it "prints a generic error if gem git source is not checked out" do
- gemfile <<-G
- source "https://gem.repo1"
- gem "rails", git: "git@github.com:rails/rails.git"
- G
-
- bundle :check, raise_on_error: false
- expect(exitstatus).to eq 1
- expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
- end
-
it "prints a generic message if you changed your lockfile" do
build_repo2 do
build_gem "rails_pinned_to_old_activesupport" do |s|
@@ -89,25 +78,25 @@ RSpec.describe "bundle check" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'rails'
G
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
gem "rails_pinned_to_old_activesupport"
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
- it "remembers --without option from install", bundler: "< 3" do
+ it "remembers --without option from install", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :foo do
- gem "myrack"
+ gem "rack"
end
G
@@ -119,9 +108,9 @@ RSpec.describe "bundle check" do
it "uses the without setting" do
bundle "config set without foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :foo do
- gem "myrack"
+ gem "rack"
end
G
@@ -131,63 +120,63 @@ RSpec.describe "bundle check" do
it "ensures that gems are actually installed and not just cached" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :group => :foo
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :group => :foo
G
bundle "config set --local without foo"
bundle :install
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "check", raise_on_error: false
- expect(err).to include("* myrack (1.0.0)")
+ bundle "check", :raise_on_error => false
+ expect(err).to include("* rack (1.0.0)")
expect(exitstatus).to eq(1)
end
it "ensures that gems are actually installed and not just cached in applications' cache" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set --local path vendor/bundle"
bundle :cache
- gem_command "uninstall myrack", env: { "GEM_HOME" => vendored_gems.to_s }
+ gem_command "uninstall rack", :env => { "GEM_HOME" => vendored_gems.to_s }
- bundle "check", raise_on_error: false
- expect(err).to include("* myrack (1.0.0)")
+ bundle "check", :raise_on_error => false
+ expect(err).to include("* rack (1.0.0)")
expect(exitstatus).to eq(1)
end
it "ignores missing gems restricted to other platforms" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
platforms :#{not_local_tag} do
gem "activesupport"
end
G
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
activesupport (2.3.5)
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
- #{generic_local_platform}
+ #{local}
#{not_local}
DEPENDENCIES
- myrack
+ rack
activesupport
G
@@ -197,28 +186,28 @@ RSpec.describe "bundle check" do
it "works with env conditionals" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
env :NOT_GOING_TO_BE_SET do
gem "activesupport"
end
G
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
activesupport (2.3.5)
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
- #{generic_local_platform}
+ #{local}
#{not_local}
DEPENDENCIES
- myrack
+ rack
activesupport
G
@@ -227,20 +216,20 @@ RSpec.describe "bundle check" do
end
it "outputs an error when the default Gemfile is not found" do
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(exitstatus).to eq(10)
expect(err).to include("Could not locate Gemfile")
end
it "does not output fatal error message" do
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(exitstatus).to eq(10)
expect(err).not_to include("Unfortunately, a fatal error has occurred. ")
end
it "fails when there's no lock file and frozen is set" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
@@ -248,15 +237,15 @@ RSpec.describe "bundle check" do
bundle "install"
FileUtils.rm(bundled_app_lock)
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(last_command).to be_failure
end
- context "--path", bundler: "< 3" do
+ context "--path", :bundler => "< 3" do
context "after installing gems in the proper directory" do
before do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
bundle "install --path vendor/bundle"
@@ -278,11 +267,11 @@ RSpec.describe "bundle check" do
context "after installing gems on a different directory" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle "check --path vendor/bundle", raise_on_error: false
+ bundle "check --path vendor/bundle", :raise_on_error => false
end
it "returns false" do
@@ -294,10 +283,10 @@ RSpec.describe "bundle check" do
describe "when locked" do
before :each do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0"
G
end
@@ -309,63 +298,63 @@ RSpec.describe "bundle check" do
it "shows what is missing with the current Gemfile if it is not satisfied" do
simulate_new_machine
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to match(/The following gems are missing/)
- expect(err).to include("* myrack (1.0")
+ expect(err).to include("* rack (1.0")
end
end
describe "when locked with multiple dependents with different requirements" do
before :each do
build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack", ">= 1.0"
+ build_gem "depends_on_rack" do |s|
+ s.add_dependency "rack", ">= 1.0"
end
- build_gem "also_depends_on_myrack" do |s|
- s.add_dependency "myrack", "~> 1.0"
+ build_gem "also_depends_on_rack" do |s|
+ s.add_dependency "rack", "~> 1.0"
end
- build_gem "myrack"
+ build_gem "rack"
end
gemfile <<-G
- source "https://gem.repo4"
- gem "depends_on_myrack"
- gem "also_depends_on_myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "depends_on_rack"
+ gem "also_depends_on_rack"
G
bundle "lock"
end
it "shows what is missing with the current Gemfile without duplications" do
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to match(/The following gems are missing/)
- expect(err).to include("* myrack (1.0").once
+ expect(err).to include("* rack (1.0").once
end
end
describe "when locked under multiple platforms" do
before :each do
build_repo4 do
- build_gem "myrack"
+ build_gem "rack"
end
gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
ruby
- #{local_platform}
+ #{specific_local_platform}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
#{Bundler::VERSION}
@@ -373,24 +362,24 @@ RSpec.describe "bundle check" do
end
it "shows what is missing with the current Gemfile without duplications" do
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to match(/The following gems are missing/)
- expect(err).to include("* myrack (1.0").once
+ expect(err).to include("* rack (1.0").once
end
end
describe "when using only scoped rubygems sources" do
before do
gemfile <<~G
- source "https://gem.repo2"
- source "https://gem.repo1" do
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ source "#{file_uri_for(gem_repo1)}" do
+ gem "rack"
end
G
end
it "returns success when the Gemfile is satisfied" do
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
bundle :check
expect(out).to include("The Gemfile's dependencies are satisfied")
end
@@ -399,49 +388,43 @@ RSpec.describe "bundle check" do
describe "when using only scoped rubygems sources with indirect dependencies" do
before do
build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack" do |s|
+ s.add_dependency "rack"
end
- build_gem "myrack"
+ build_gem "rack"
end
gemfile <<~G
- source "https://gem.repo1"
- source "https://gem.repo4" do
- gem "depends_on_myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo4)}" do
+ gem "depends_on_rack"
end
G
end
it "returns success when the Gemfile is satisfied and generates a correct lockfile" do
- system_gems "depends_on_myrack-1.0", "myrack-1.0", gem_repo: gem_repo4, path: default_bundle_path
+ system_gems "depends_on_rack-1.0", "rack-1.0", :gem_repo => gem_repo4, :path => default_bundle_path
bundle :check
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "depends_on_myrack", "1.0"
- c.no_checksum "myrack", "1.0"
- end
-
expect(out).to include("The Gemfile's dependencies are satisfied")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- depends_on_myrack (1.0)
- myrack
- myrack (1.0)
+ depends_on_rack (1.0)
+ rack
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- depends_on_myrack!
- #{checksums}
+ depends_on_rack!
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -458,7 +441,7 @@ RSpec.describe "bundle check" do
build_gem "dex-dispatch-engine"
end
- build_lib("bundle-check-issue", path: tmp("bundle-check-issue")) do |s|
+ build_lib("bundle-check-issue", :path => tmp.join("bundle-check-issue")) do |s|
s.write "Gemfile", <<-G
source "https://localgemserver.test"
@@ -472,24 +455,16 @@ RSpec.describe "bundle check" do
s.add_dependency "awesome_print"
end
- bundle "install", artifice: "compact_index_extra", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, dir: tmp("bundle-check-issue")
+ bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, :dir => tmp.join("bundle-check-issue")
end
it "does not corrupt lockfile when changing version" do
- version_file = tmp("bundle-check-issue/bundle-check-issue.gemspec")
+ version_file = tmp.join("bundle-check-issue/bundle-check-issue.gemspec")
File.write(version_file, File.read(version_file).gsub(/s\.version = .+/, "s.version = '9999'"))
- bundle "check --verbose", dir: tmp("bundle-check-issue")
+ bundle "check --verbose", :dir => tmp.join("bundle-check-issue")
- lockfile = File.read(tmp("bundle-check-issue/Gemfile.lock"))
-
- checksums = checksums_section_when_enabled(lockfile) do |c|
- c.checksum gem_repo4, "awesome_print", "1.0"
- c.no_checksum "bundle-check-issue", "9999"
- c.checksum gem_repo2, "dex-dispatch-engine", "1.0"
- end
-
- expect(lockfile).to eq <<~L
+ expect(File.read(tmp.join("bundle-check-issue/Gemfile.lock"))).to eq <<~L
PATH
remote: .
specs:
@@ -512,7 +487,7 @@ RSpec.describe "bundle check" do
DEPENDENCIES
bundle-check-issue!
dex-dispatch-engine!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -523,15 +498,15 @@ RSpec.describe "bundle check" do
def lock_with(bundler_version = nil)
lock = <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
L
if bundler_version
@@ -545,8 +520,8 @@ RSpec.describe "bundle check" do
bundle "config set --local path vendor/bundle"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb
index c27766835e..471cd6c354 100644
--- a/spec/bundler/commands/clean_spec.rb
+++ b/spec/bundler/commands/clean_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe "bundle clean" do
it "removes unused gems that are different" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -30,7 +30,7 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
G
@@ -40,17 +40,17 @@ RSpec.describe "bundle clean" do
expect(out).to include("Removing foo (1.0)")
- should_have_gems "thin-1.0", "myrack-1.0.0"
+ should_have_gems "thin-1.0", "rack-1.0.0"
should_not_have_gems "foo-1.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "removes old version of gem if unused" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "0.9.1"
+ gem "rack", "0.9.1"
gem "foo"
G
@@ -59,28 +59,28 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
gem "foo"
G
bundle "install"
bundle :clean
- expect(out).to include("Removing myrack (0.9.1)")
+ expect(out).to include("Removing rack (0.9.1)")
- should_have_gems "foo-1.0", "myrack-1.0.0"
- should_not_have_gems "myrack-0.9.1"
+ should_have_gems "foo-1.0", "rack-1.0.0"
+ should_not_have_gems "rack-0.9.1"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "removes new version of gem if unused" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
gem "foo"
G
@@ -89,31 +89,31 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "0.9.1"
+ gem "rack", "0.9.1"
gem "foo"
G
- bundle "update myrack"
+ bundle "update rack"
bundle :clean
- expect(out).to include("Removing myrack (1.0.0)")
+ expect(out).to include("Removing rack (1.0.0)")
- should_have_gems "foo-1.0", "myrack-0.9.1"
- should_not_have_gems "myrack-1.0.0"
+ should_have_gems "foo-1.0", "rack-0.9.1"
+ should_not_have_gems "rack-1.0.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "removes gems in bundle without groups" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
group :test_group do
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
end
G
@@ -123,12 +123,12 @@ RSpec.describe "bundle clean" do
bundle "install"
bundle :clean
- expect(out).to include("Removing myrack (1.0.0)")
+ expect(out).to include("Removing rack (1.0.0)")
should_have_gems "foo-1.0"
- should_not_have_gems "myrack-1.0.0"
+ should_not_have_gems "rack-1.0.0"
- expect(vendored_gems("bin/myrackup")).to_not exist
+ expect(vendored_gems("bin/rackup")).to_not exist
end
it "does not remove cached git dir if it's being used" do
@@ -137,9 +137,9 @@ RSpec.describe "bundle clean" do
git_path = lib_path("foo-1.0")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
git "#{git_path}", :ref => "#{revision}" do
gem "foo"
end
@@ -156,14 +156,14 @@ RSpec.describe "bundle clean" do
end
it "removes unused git gems" do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
git_path = lib_path("foo")
revision = revision_for(git_path)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
git "#{git_path}", :ref => "#{revision}" do
gem "foo"
end
@@ -173,9 +173,9 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
bundle "install"
@@ -183,25 +183,25 @@ RSpec.describe "bundle clean" do
expect(out).to include("Removing foo (#{revision[0..11]})")
- expect(vendored_gems("gems/myrack-1.0.0")).to exist
+ expect(vendored_gems("gems/rack-1.0.0")).to exist
expect(vendored_gems("bundler/gems/foo-#{revision[0..11]}")).not_to exist
digest = Digest(:SHA1).hexdigest(git_path.to_s)
expect(vendored_gems("cache/bundler/git/foo-#{digest}")).not_to exist
- expect(vendored_gems("specifications/myrack-1.0.0.gemspec")).to exist
+ expect(vendored_gems("specifications/rack-1.0.0.gemspec")).to exist
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "keeps used git gems even if installed to a symlinked location" do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
git_path = lib_path("foo")
revision = revision_for(git_path)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
git "#{git_path}", :ref => "#{revision}" do
gem "foo"
end
@@ -221,13 +221,13 @@ RSpec.describe "bundle clean" do
end
it "removes old git gems" do
- build_git "foo-bar", path: lib_path("foo-bar")
+ build_git "foo-bar", :path => lib_path("foo-bar")
revision = revision_for(lib_path("foo-bar"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
git "#{lib_path("foo-bar")}" do
gem "foo-bar"
end
@@ -236,32 +236,32 @@ RSpec.describe "bundle clean" do
bundle "config set path vendor/bundle"
bundle "install"
- update_git "foo-bar", path: lib_path("foo-bar")
+ update_git "foo-bar", :path => lib_path("foo-bar")
revision2 = revision_for(lib_path("foo-bar"))
- bundle "update", all: true
+ bundle "update", :all => true
bundle :clean
expect(out).to include("Removing foo-bar (#{revision[0..11]})")
- expect(vendored_gems("gems/myrack-1.0.0")).to exist
+ expect(vendored_gems("gems/rack-1.0.0")).to exist
expect(vendored_gems("bundler/gems/foo-bar-#{revision[0..11]}")).not_to exist
expect(vendored_gems("bundler/gems/foo-bar-#{revision2[0..11]}")).to exist
- expect(vendored_gems("specifications/myrack-1.0.0.gemspec")).to exist
+ expect(vendored_gems("specifications/rack-1.0.0.gemspec")).to exist
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "does not remove nested gems in a git repo" do
- build_lib "activesupport", "3.0", path: lib_path("rails/activesupport")
- build_git "rails", "3.0", path: lib_path("rails") do |s|
+ build_lib "activesupport", "3.0", :path => lib_path("rails/activesupport")
+ build_git "rails", "3.0", :path => lib_path("rails") do |s|
s.add_dependency "activesupport", "= 3.0"
end
revision = revision_for(lib_path("rails"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", :git => "#{lib_path("rails")}", :ref => '#{revision}'
G
@@ -274,14 +274,14 @@ RSpec.describe "bundle clean" do
end
it "does not remove git sources that are in without groups" do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
git_path = lib_path("foo")
revision = revision_for(git_path)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
group :test do
git "#{git_path}", :ref => "#{revision}" do
gem "foo"
@@ -302,9 +302,9 @@ RSpec.describe "bundle clean" do
it "does not blow up when using without groups" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
group :development do
gem "foo"
@@ -321,12 +321,12 @@ RSpec.describe "bundle clean" do
it "displays an error when used without --path" do
bundle "config set path.system true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
- bundle :clean, raise_on_error: false
+ bundle :clean, :raise_on_error => false
expect(exitstatus).to eq(15)
expect(err).to include("--force")
@@ -335,7 +335,7 @@ RSpec.describe "bundle clean" do
# handling bundle clean upgrade path from the pre's
it "removes .gem/.gemspec file even if there's no corresponding gem dir" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -345,71 +345,71 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
bundle "install"
- FileUtils.rm(vendored_gems("bin/myrackup"))
+ FileUtils.rm(vendored_gems("bin/rackup"))
FileUtils.rm_rf(vendored_gems("gems/thin-1.0"))
- FileUtils.rm_rf(vendored_gems("gems/myrack-1.0.0"))
+ FileUtils.rm_rf(vendored_gems("gems/rack-1.0.0"))
bundle :clean
- should_not_have_gems "thin-1.0", "myrack-1.0"
+ should_not_have_gems "thin-1.0", "rack-1.0"
should_have_gems "foo-1.0"
- expect(vendored_gems("bin/myrackup")).not_to exist
+ expect(vendored_gems("bin/rackup")).not_to exist
end
it "does not call clean automatically when using system gems" do
bundle "config set path.system true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
- gem "myrack"
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
gem_command :list
- expect(out).to include("myrack (1.0.0)").and include("thin (1.0)")
+ expect(out).to include("rack (1.0.0)").and include("thin (1.0)")
end
- it "--clean should override the bundle setting on install", bundler: "< 3" do
+ it "--clean should override the bundle setting on install", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
- gem "myrack"
+ gem "rack"
G
bundle "config set path vendor/bundle"
bundle "config set clean false"
bundle "install --clean true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle "install"
- should_have_gems "myrack-1.0.0"
+ should_have_gems "rack-1.0.0"
should_not_have_gems "thin-1.0"
end
- it "--clean should override the bundle setting on update", bundler: "< 3" do
+ it "--clean should override the bundle setting on update", :bundler => "< 3" do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "foo"
G
@@ -421,17 +421,17 @@ RSpec.describe "bundle clean" do
build_gem "foo", "1.0.1"
end
- bundle "update", all: true
+ bundle "update", :all => true
should_have_gems "foo-1.0.1"
should_not_have_gems "foo-1.0"
end
- it "automatically cleans when path has not been set", bundler: "3" do
+ it "automatically cleans when path has not been set", :bundler => "3" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "foo"
G
@@ -440,7 +440,7 @@ RSpec.describe "bundle clean" do
build_gem "foo", "1.0.1"
end
- bundle "update", all: true
+ bundle "update", :all => true
files = Pathname.glob(bundled_app(".bundle", Bundler.ruby_scope, "*", "*"))
files.map! {|f| f.to_s.sub(bundled_app(".bundle", Bundler.ruby_scope).to_s, "") }
@@ -453,29 +453,29 @@ RSpec.describe "bundle clean" do
it "does not clean automatically on --path" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
- gem "myrack"
+ gem "rack"
G
bundle "config set path vendor/bundle"
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle "install"
- should_have_gems "myrack-1.0.0", "thin-1.0"
+ should_have_gems "rack-1.0.0", "thin-1.0"
end
it "does not clean on bundle update with --path" do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "foo"
G
@@ -486,7 +486,7 @@ RSpec.describe "bundle clean" do
build_gem "foo", "1.0.1"
end
- bundle :update, all: true
+ bundle :update, :all => true
should_have_gems "foo-1.0", "foo-1.0.1"
end
@@ -496,7 +496,7 @@ RSpec.describe "bundle clean" do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "foo"
G
@@ -505,7 +505,7 @@ RSpec.describe "bundle clean" do
update_repo2 do
build_gem "foo", "1.0.1"
end
- bundle :update, all: true
+ bundle :update, :all => true
gem_command :list
expect(out).to include("foo (1.0.1, 1.0)")
@@ -515,17 +515,17 @@ RSpec.describe "bundle clean" do
bundle "config set path.system true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
- gem "myrack"
+ gem "rack"
G
bundle :install
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle :install
bundle "clean --force"
@@ -533,7 +533,7 @@ RSpec.describe "bundle clean" do
expect(out).to include("Removing foo (1.0)")
gem_command :list
expect(out).not_to include("foo (1.0)")
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
describe "when missing permissions", :permissions do
@@ -544,30 +544,30 @@ RSpec.describe "bundle clean" do
end
it "returns a helpful error message" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
- gem "myrack"
+ gem "rack"
G
bundle :install
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle :install
FileUtils.chmod(0o500, system_cache_path)
- bundle :clean, force: true, raise_on_error: false
+ bundle :clean, :force => true, :raise_on_error => false
expect(err).to include(system_gem_path.to_s)
expect(err).to include("grant write permissions")
gem_command :list
expect(out).to include("foo (1.0)")
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
end
@@ -576,7 +576,7 @@ RSpec.describe "bundle clean" do
revision = revision_for(lib_path("foo-1.0"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -612,7 +612,7 @@ RSpec.describe "bundle clean" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "bindir"
G
@@ -626,21 +626,25 @@ RSpec.describe "bundle clean" do
end
it "when using --force, it doesn't remove default gem binaries", :realworld do
- default_irb_version = ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", raise_on_error: false
+ skip "does not work on old rubies because the realworld gems that need to be installed don't support them" if RUBY_VERSION < "2.7.0"
+
+ skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2
+
+ default_irb_version = ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", :raise_on_error => false
skip "irb isn't a default gem" if default_irb_version.empty?
# simulate executable for default gem
- build_gem "irb", default_irb_version, to_system: true, default: true do |s|
+ build_gem "irb", default_irb_version, :to_system => true, :default => true do |s|
s.executables = "irb"
end
realworld_system_gems "tsort --version 0.1.0", "pathname --version 0.1.0", "set --version 1.0.1"
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
G
- bundle "clean --force", env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
+ bundle "clean --force", :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
expect(out).not_to include("Removing irb")
end
@@ -654,7 +658,7 @@ RSpec.describe "bundle clean" do
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
gem "bar", "1.0", :path => "#{relative_path}"
@@ -667,7 +671,7 @@ RSpec.describe "bundle clean" do
it "doesn't remove gems in dry-run mode with path set" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -678,7 +682,7 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
G
@@ -690,14 +694,14 @@ RSpec.describe "bundle clean" do
expect(out).not_to include("Removing foo (1.0)")
expect(out).to include("Would have removed foo (1.0)")
- should_have_gems "thin-1.0", "myrack-1.0.0", "foo-1.0"
+ should_have_gems "thin-1.0", "rack-1.0.0", "foo-1.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "doesn't remove gems in dry-run mode with no path set" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -708,7 +712,7 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
G
@@ -720,14 +724,14 @@ RSpec.describe "bundle clean" do
expect(out).not_to include("Removing foo (1.0)")
expect(out).to include("Would have removed foo (1.0)")
- should_have_gems "thin-1.0", "myrack-1.0.0", "foo-1.0"
+ should_have_gems "thin-1.0", "rack-1.0.0", "foo-1.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "doesn't store dry run as a config setting" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -739,7 +743,7 @@ RSpec.describe "bundle clean" do
bundle "config set dry_run false"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
G
@@ -751,15 +755,15 @@ RSpec.describe "bundle clean" do
expect(out).to include("Removing foo (1.0)")
expect(out).not_to include("Would have removed foo (1.0)")
- should_have_gems "thin-1.0", "myrack-1.0.0"
+ should_have_gems "thin-1.0", "rack-1.0.0"
should_not_have_gems "foo-1.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -770,7 +774,7 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "weakling"
@@ -779,7 +783,7 @@ RSpec.describe "bundle clean" do
bundle "config set auto_install 1"
bundle :clean
expect(out).to include("Installing weakling 0.0.3")
- should_have_gems "thin-1.0", "myrack-1.0.0", "weakling-0.0.3"
+ should_have_gems "thin-1.0", "rack-1.0.0", "weakling-0.0.3"
should_not_have_gems "foo-1.0"
end
@@ -789,7 +793,7 @@ RSpec.describe "bundle clean" do
revision = revision_for(lib_path("very_simple_git_binary-1.0"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
G
@@ -808,7 +812,7 @@ RSpec.describe "bundle clean" do
it "removes extension directories" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "very_simple_binary"
@@ -828,7 +832,7 @@ RSpec.describe "bundle clean" do
expect(simple_binary_extensions_dir).to exist
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "simple_binary"
@@ -849,7 +853,7 @@ RSpec.describe "bundle clean" do
short_revision = revision[0..11]
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
@@ -864,7 +868,7 @@ RSpec.describe "bundle clean" do
expect(very_simple_binary_extensions_dir).to exist
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
G
@@ -874,7 +878,7 @@ RSpec.describe "bundle clean" do
expect(very_simple_binary_extensions_dir).to exist
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
bundle "install"
@@ -891,7 +895,7 @@ RSpec.describe "bundle clean" do
short_revision = revision[0..11]
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :development do
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
@@ -901,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/config_spec.rb b/spec/bundler/commands/config_spec.rb
index 1392b17315..ede93f99eb 100644
--- a/spec/bundler/commands/config_spec.rb
+++ b/spec/bundler/commands/config_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe ".bundle/config" do
context "with env overwrite" do
it "prints config with env" do
- bundle "config list --parseable", env: { "BUNDLE_FOO" => "bar3" }
+ bundle "config list --parseable", :env => { "BUNDLE_FOO" => "bar3" }
expect(out).to include("foo=bar3")
end
end
@@ -38,8 +38,8 @@ RSpec.describe ".bundle/config" do
describe "location with a gemfile" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -56,7 +56,7 @@ RSpec.describe ".bundle/config" do
expect(bundled_app(".bundle")).not_to exist
expect(tmp("foo/bar/config")).to exist
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "can provide a relative path with the environment variable" do
@@ -64,11 +64,11 @@ RSpec.describe ".bundle/config" do
ENV["BUNDLE_APP_CONFIG"] = "../foo"
bundle "config set --local path vendor/bundle"
- bundle "install", dir: bundled_app("omg")
+ bundle "install", :dir => bundled_app("omg")
expect(bundled_app(".bundle")).not_to exist
expect(bundled_app("../foo/config")).to exist
- expect(the_bundle).to include_gems "myrack 1.0.0", dir: bundled_app("omg")
+ expect(the_bundle).to include_gems "rack 1.0.0", :dir => bundled_app("omg")
end
end
@@ -79,14 +79,6 @@ RSpec.describe ".bundle/config" do
expect(home(".bundle/config")).to exist
end
- it "does not list global settings as local" do
- bundle "config set --global foo bar"
- bundle "config list", dir: home
-
- expect(out).to include("for the current user")
- expect(out).not_to include("for your local app")
- end
-
it "works with an absolute path" do
ENV["BUNDLE_APP_CONFIG"] = tmp("foo/bar").to_s
bundle "config set --local path vendor/bundle"
@@ -104,8 +96,8 @@ RSpec.describe ".bundle/config" do
end
it "can be configured through BUNDLE_USER_CONFIG" do
- bundle "config set path vendor", env: { "BUNDLE_USER_CONFIG" => bundle_user_config }
- bundle "config get path", env: { "BUNDLE_USER_CONFIG" => bundle_user_config }
+ bundle "config set path vendor", :env => { "BUNDLE_USER_CONFIG" => bundle_user_config }
+ bundle "config get path", :env => { "BUNDLE_USER_CONFIG" => bundle_user_config }
expect(out).to include("Set for the current user (#{bundle_user_config}): \"vendor\"")
end
@@ -113,8 +105,8 @@ RSpec.describe ".bundle/config" do
let(:bundle_user_home) { bundled_app(".bundle").to_s }
it "uses the right location" do
- bundle "config set path vendor", env: { "BUNDLE_USER_HOME" => bundle_user_home }
- bundle "config get path", env: { "BUNDLE_USER_HOME" => bundle_user_home }
+ bundle "config set path vendor", :env => { "BUNDLE_USER_HOME" => bundle_user_home }
+ bundle "config get path", :env => { "BUNDLE_USER_HOME" => bundle_user_home }
expect(out).to include("Set for the current user (#{bundle_user_home}/config): \"vendor\"")
end
end
@@ -123,8 +115,8 @@ RSpec.describe ".bundle/config" do
describe "global" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -215,8 +207,8 @@ RSpec.describe ".bundle/config" do
describe "local" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -271,8 +263,8 @@ RSpec.describe ".bundle/config" do
describe "env" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -344,8 +336,8 @@ RSpec.describe ".bundle/config" do
describe "gem mirrors" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -358,16 +350,10 @@ end
E
expect(out).to eq("http://gems.example.org/ => http://gem-mirror.example.org/")
end
-
- it "allows configuring fallback timeout for each mirror, and does not duplicate configs", rubygems: ">= 3.5.12" do
- bundle "config set --global mirror.https://rubygems.org.fallback_timeout 1"
- bundle "config set --global mirror.https://rubygems.org.fallback_timeout 2"
- expect(File.read(home(".bundle/config"))).to include("BUNDLE_MIRROR").once
- end
end
describe "quoting" do
- before(:each) { gemfile "source 'https://gem.repo1'" }
+ before(:each) { gemfile "source \"#{file_uri_for(gem_repo1)}\"" }
let(:long_string) do
"--with-xml2-include=/usr/pkg/include/libxml2 --with-xml2-lib=/usr/pkg/lib " \
"--with-xslt-dir=/usr/pkg"
@@ -417,8 +403,8 @@ E
describe "very long lines" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -453,11 +439,11 @@ E
it "does not make bundler crash and ignores the configuration" do
bundle "config list --parseable"
- expect(out).to be_empty
+ expect(out).to eq("#mirror.https://rails-assets.org/=http://localhost:9292")
expect(err).to be_empty
ruby(<<~RUBY)
- require "bundler"
+ require "#{entrypoint}"
print Bundler.settings.mirror_for("https://rails-assets.org")
RUBY
expect(out).to eq("https://rails-assets.org/")
@@ -465,7 +451,7 @@ E
bundle "config set mirror.all http://localhost:9293"
ruby(<<~RUBY)
- require "bundler"
+ require "#{entrypoint}"
print Bundler.settings.mirror_for("https://rails-assets.org")
RUBY
expect(out).to eq("http://localhost:9293/")
@@ -475,26 +461,26 @@ E
describe "subcommands" do
it "list" do
- bundle "config list", env: { "BUNDLE_FOO" => "bar" }
+ bundle "config list", :env => { "BUNDLE_FOO" => "bar" }
expect(out).to eq "Settings are listed in order of priority. The top value will be used.\nfoo\nSet via BUNDLE_FOO: \"bar\""
- bundle "config list", env: { "BUNDLE_FOO" => "bar" }, parseable: true
+ bundle "config list", :env => { "BUNDLE_FOO" => "bar" }, :parseable => true
expect(out).to eq "foo=bar"
end
it "list with credentials" do
- bundle "config list", env: { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
+ bundle "config list", :env => { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
expect(out).to eq "Settings are listed in order of priority. The top value will be used.\ngems.myserver.com\nSet via BUNDLE_GEMS__MYSERVER__COM: \"user:[REDACTED]\""
- bundle "config list", parseable: true, env: { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
+ bundle "config list", :parseable => true, :env => { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
expect(out).to eq "gems.myserver.com=user:password"
end
it "list with API token credentials" do
- bundle "config list", env: { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
+ bundle "config list", :env => { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
expect(out).to eq "Settings are listed in order of priority. The top value will be used.\ngems.myserver.com\nSet via BUNDLE_GEMS__MYSERVER__COM: \"[REDACTED]:x-oauth-basic\""
- bundle "config list", parseable: true, env: { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
+ bundle "config list", :parseable => true, :env => { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
expect(out).to eq "gems.myserver.com=api_token:x-oauth-basic"
end
@@ -529,7 +515,7 @@ E
bundle "config set --local foo 4.1"
expect(out).to eq "You are replacing the current local value of foo, which is currently \"4\""
- bundle "config set --global --local foo 5", raise_on_error: false
+ bundle "config set --global --local foo 5", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to eq "The options global and local were specified. Please only use one of the switches at a time."
end
@@ -569,7 +555,7 @@ E
expect(out).to eq ""
expect(bundle("config get foo")).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
- bundle "config unset foo --local --global", raise_on_error: false
+ bundle "config unset foo --local --global", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to eq "The options global and local were specified. Please only use one of the switches at a time."
end
@@ -580,8 +566,8 @@ RSpec.describe "setting gemfile via config" do
context "when only the non-default Gemfile exists" do
it "persists the gemfile location to .bundle/config" do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
diff --git a/spec/bundler/commands/console_spec.rb b/spec/bundler/commands/console_spec.rb
index 8b02e7aa1b..aa76096e3d 100644
--- a/spec/bundler/commands/console_spec.rb
+++ b/spec/bundler/commands/console_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "bundle console", bundler: "< 3", readline: true do
+RSpec.describe "bundle console", :bundler => "< 3", :readline => true do
before :each do
build_repo2 do
# A minimal fake pry console
@@ -38,16 +38,16 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
end
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
G
end
it "starts IRB with the default group loaded" do
bundle "console" do |input, _, _|
- input.puts("puts MYRACK")
+ input.puts("puts RACK")
input.puts("exit")
end
expect(out).to include("0.9.1")
@@ -63,7 +63,7 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
it "starts another REPL if configured as such" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "pry"
G
bundle "config set console pry"
@@ -105,7 +105,7 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
it "loads the default group" do
bundle "console test" do |input, _, _|
- input.puts("puts MYRACK")
+ input.puts("puts RACK")
input.puts("exit")
end
expect(out).to include("0.9.1")
@@ -113,7 +113,7 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
it "doesn't load other groups" do
bundle "console test" do |input, _, _|
- input.puts("puts MYRACK_MIDDLEWARE")
+ input.puts("puts RACK_MIDDLEWARE")
input.puts("exit")
end
expect(out).to include("NameError")
@@ -122,10 +122,10 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
gem "foo"
G
diff --git a/spec/bundler/commands/doctor_spec.rb b/spec/bundler/commands/doctor_spec.rb
index 744510cd40..1afac00923 100644
--- a/spec/bundler/commands/doctor_spec.rb
+++ b/spec/bundler/commands/doctor_spec.rb
@@ -8,8 +8,8 @@ require "bundler/cli/doctor"
RSpec.describe "bundle doctor" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
@stdout = StringIO.new
@@ -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
@@ -52,7 +47,7 @@ RSpec.describe "bundle doctor" do
it "exits with no message if the installed gem's C extension dylib breakage is fine" do
doctor = Bundler::CLI::Doctor.new({})
- expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/myrack/myrack.bundle"]
+ 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/lib/libSystem.dylib"]
allow(Fiddle).to receive(:dlopen).with("/usr/lib/libSystem.dylib").and_return(true)
expect { doctor.run }.not_to raise_error
@@ -61,13 +56,13 @@ RSpec.describe "bundle doctor" do
it "exits with a message if one of the linked libraries is missing" do
doctor = Bundler::CLI::Doctor.new({})
- expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/myrack/myrack.bundle"]
+ 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
- * myrack: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
+ * rack: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
E
end
end
diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb
index ca8ef26344..5ca11dcba2 100644
--- a/spec/bundler/commands/exec_spec.rb
+++ b/spec/bundler/commands/exec_spec.rb
@@ -1,99 +1,116 @@
# frozen_string_literal: true
RSpec.describe "bundle exec" do
- let(:system_gems_to_install) { %w[myrack-1.0.0 myrack-0.9.1] }
+ let(:system_gems_to_install) { %w[rack-1.0.0 rack-0.9.1] }
it "works with --gemfile flag" do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
- gemfile "CustomGemfile", <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ create_file "CustomGemfile", <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
- bundle "exec --gemfile CustomGemfile myrackup"
+ bundle "exec --gemfile CustomGemfile rackup"
expect(out).to eq("1.0.0")
end
it "activates the correct gem" do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to eq("0.9.1")
end
it "works and prints no warnings when HOME is not writable" do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- bundle "exec myrackup", env: { "HOME" => "/" }
+ bundle "exec rackup", :env => { "HOME" => "/" }
expect(out).to eq("0.9.1")
expect(err).to be_empty
end
it "works when the bins are in ~/.bundle" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to eq("1.0.0")
end
it "works when running from a random directory" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "exec 'cd #{tmp("gems")} && myrackup'"
+ bundle "exec 'cd #{tmp("gems")} && rackup'"
expect(out).to eq("1.0.0")
end
it "works when exec'ing something else" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec echo exec"
expect(out).to eq("exec")
end
it "works when exec'ing to ruby" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec ruby -e 'puts %{hi}'"
expect(out).to eq("hi")
end
it "works when exec'ing to rubygems" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec #{gem_cmd} --version"
expect(out).to eq(Gem::VERSION)
end
it "works when exec'ing to rubygems through sh -c" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec sh -c '#{gem_cmd} --version'"
expect(out).to eq(Gem::VERSION)
end
- it "works when exec'ing back to bundler to run a remote resolve" do
+ it "works when exec'ing back to bundler with a lockfile that doesn't include the current platform" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- bundle "exec bundle lock", env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ # simulate lockfile generated with old version not including specific platform
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ rack (0.9.1)
- expect(out).to include("Writing lockfile")
+ PLATFORMS
+ RUBY
+
+ DEPENDENCIES
+ rack (= 0.9.1)
+
+ BUNDLED WITH
+ 2.1.4
+ L
+
+ bundle "exec bundle cache", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+
+ expect(out).to include("Updating files in vendor/cache")
end
it "respects custom process title when loading through ruby" do
@@ -103,20 +120,20 @@ RSpec.describe "bundle exec" do
Process.setproctitle("1-2-3-4-5-6-7")
puts `ps -ocommand= -p#{$$}`
RUBY
- gemfile "Gemfile", "source \"https://gem.repo1\""
+ create_file "Gemfile", "source \"#{file_uri_for(gem_repo1)}\""
create_file "a.rb", script_that_changes_its_own_title_and_checks_if_picked_up_by_ps_unix_utility
bundle "exec ruby a.rb"
expect(out).to eq("1-2-3-4-5-6-7")
end
it "accepts --verbose" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec --verbose echo foobar"
expect(out).to eq("foobar")
end
it "passes --verbose to command if it is given after the command" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec echo --verbose"
expect(out).to eq("--verbose")
end
@@ -140,7 +157,7 @@ RSpec.describe "bundle exec" do
end
G
- install_gemfile "source \"https://gem.repo1\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
sys_exec "#{Gem.ruby} #{command.path}"
expect(out).to be_empty
@@ -148,7 +165,7 @@ RSpec.describe "bundle exec" do
end
it "accepts --keep-file-descriptors" do
- install_gemfile "source \"https://gem.repo1\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
bundle "exec --keep-file-descriptors echo foobar"
expect(err).to be_empty
@@ -157,7 +174,7 @@ RSpec.describe "bundle exec" do
it "can run a command named --verbose" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
File.open(bundled_app("--verbose"), "w") do |f|
f.puts "#!/bin/sh"
f.puts "echo foobar"
@@ -171,37 +188,37 @@ RSpec.describe "bundle exec" do
it "handles different versions in different bundles" do
build_repo2 do
- build_gem "myrack_two", "1.0.0" do |s|
- s.executables = "myrackup"
+ build_gem "rack_two", "1.0.0" do |s|
+ s.executables = "rackup"
end
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
- source "https://gem.repo2"
- gem "myrack_two", "1.0.0"
+ install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack_two", "1.0.0"
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to eq("0.9.1")
- bundle "exec myrackup", dir: bundled_app2
+ bundle "exec rackup", :dir => bundled_app2
expect(out).to eq("1.0.0")
end
context "with default gems" do
- let(:default_irb_version) { ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", raise_on_error: false }
+ let(:default_irb_version) { ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", :raise_on_error => false }
context "when not specified in Gemfile" do
before do
skip "irb isn't a default gem" if default_irb_version.empty?
- install_gemfile "source \"https://gem.repo1\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
end
it "uses version provided by ruby" do
@@ -224,7 +241,7 @@ RSpec.describe "bundle exec" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "irb", "#{specified_irb_version}"
G
end
@@ -254,7 +271,7 @@ RSpec.describe "bundle exec" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "gem_depending_on_old_irb"
G
@@ -270,54 +287,54 @@ RSpec.describe "bundle exec" do
it "warns about executable conflicts" do
build_repo2 do
- build_gem "myrack_two", "1.0.0" do |s|
- s.executables = "myrackup"
+ build_gem "rack_two", "1.0.0" do |s|
+ s.executables = "rackup"
end
end
bundle "config set --global path.system true"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
- source "https://gem.repo2"
- gem "myrack_two", "1.0.0"
+ install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack_two", "1.0.0"
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(last_command.stderr).to eq(
- "Bundler is using a binstub that was created for a different gem (myrack).\n" \
- "You should run `bundle binstub myrack_two` to work around a system/bundle conflict."
+ "Bundler is using a binstub that was created for a different gem (rack).\n" \
+ "You should run `bundle binstub rack_two` to work around a system/bundle conflict."
)
end
it "handles gems installed with --without" do
bundle "config set --local without middleware"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack" # myrack 0.9.1 and 1.0 exist
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack" # rack 0.9.1 and 1.0 exist
group :middleware do
- gem "myrack_middleware" # myrack_middleware depends on myrack 0.9.1
+ gem "rack_middleware" # rack_middleware depends on rack 0.9.1
end
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to eq("0.9.1")
- expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
+ expect(the_bundle).not_to include_gems "rack_middleware 1.0"
end
it "does not duplicate already exec'ed RUBYOPT" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundler_setup_opt = "-r#{lib_dir}/bundler/setup"
@@ -327,7 +344,7 @@ RSpec.describe "bundle exec" do
bundle "exec 'echo $RUBYOPT'"
expect(out.split(" ").count(bundler_setup_opt)).to eq(1)
- bundle "exec 'echo $RUBYOPT'", env: { "RUBYOPT" => rubyopt }
+ bundle "exec 'echo $RUBYOPT'", :env => { "RUBYOPT" => rubyopt }
expect(out.split(" ").count(bundler_setup_opt)).to eq(1)
end
@@ -335,8 +352,8 @@ RSpec.describe "bundle exec" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
rubylib = ENV["RUBYLIB"]
@@ -346,17 +363,17 @@ RSpec.describe "bundle exec" do
bundle "exec 'echo $RUBYLIB'"
expect(out).to include(rubylib)
- bundle "exec 'echo $RUBYLIB'", env: { "RUBYLIB" => rubylib }
+ bundle "exec 'echo $RUBYLIB'", :env => { "RUBYLIB" => rubylib }
expect(out).to include(rubylib)
end
it "errors nicely when the argument doesn't exist" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "exec foobarbaz", raise_on_error: false
+ bundle "exec foobarbaz", :raise_on_error => false
expect(exitstatus).to eq(127)
expect(err).to include("bundler: command not found: foobarbaz")
expect(err).to include("Install missing gem executables with `bundle install`")
@@ -364,39 +381,39 @@ RSpec.describe "bundle exec" do
it "errors nicely when the argument is not executable" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "exec touch foo"
- bundle "exec ./foo", raise_on_error: false
+ bundle "exec ./foo", :raise_on_error => false
expect(exitstatus).to eq(126)
expect(err).to include("bundler: not executable: ./foo")
end
it "errors nicely when no arguments are passed" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "exec", raise_on_error: false
+ bundle "exec", :raise_on_error => false
expect(exitstatus).to eq(128)
expect(err).to include("bundler: exec needs a command to run")
end
it "raises a helpful error when exec'ing to something outside of the bundle" do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
- bundle "config set clean false" # want to keep the myrackup binstub
+ bundle "config set clean false" # want to keep the rackup binstub
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
[true, false].each do |l|
bundle "config set disable_exec_load #{l}"
- bundle "exec myrackup", raise_on_error: false
- expect(err).to include "can't find executable myrackup for gem myrack. myrack is not currently included in the bundle, perhaps you meant to add it to your Gemfile?"
+ bundle "exec rackup", :raise_on_error => false
+ expect(err).to include "can't find executable rackup for gem rack. rack is not currently included in the bundle, perhaps you meant to add it to your Gemfile?"
end
end
@@ -410,8 +427,8 @@ RSpec.describe "bundle exec" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
create_file("print_args", <<-'RUBY')
@@ -495,31 +512,31 @@ RSpec.describe "bundle exec" do
describe "run from a random directory" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
it "works when unlocked" do
- bundle "exec 'cd #{tmp("gems")} && myrackup'"
+ bundle "exec 'cd #{tmp("gems")} && rackup'"
expect(out).to eq("1.0.0")
end
it "works when locked" do
expect(the_bundle).to be_locked
- bundle "exec 'cd #{tmp("gems")} && myrackup'"
+ bundle "exec 'cd #{tmp("gems")} && rackup'"
expect(out).to eq("1.0.0")
end
end
describe "from gems bundled via :path" do
before(:each) do
- build_lib "fizz", path: home("fizz") do |s|
+ build_lib "fizz", :path => home("fizz") do |s|
s.executables = "fizz"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "fizz", :path => "#{File.expand_path(home("fizz"))}"
G
end
@@ -544,7 +561,7 @@ RSpec.describe "bundle exec" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "fizz_git", :git => "#{lib_path("fizz_git-1.0")}"
G
end
@@ -563,12 +580,12 @@ RSpec.describe "bundle exec" do
describe "from gems bundled via :git with no gemspec" do
before(:each) do
- build_git "fizz_no_gemspec", gemspec: false do |s|
+ build_git "fizz_no_gemspec", :gemspec => false do |s|
s.executables = "fizz_no_gemspec"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "fizz_no_gemspec", "1.0", :git => "#{lib_path("fizz_no_gemspec-1.0")}"
G
end
@@ -588,35 +605,18 @@ RSpec.describe "bundle exec" do
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
gem "foo"
G
bundle "config set auto_install 1"
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to include("Installing foo 1.0")
end
- it "performs an automatic bundle install with git gems" do
- build_git "foo" do |s|
- s.executables = "foo"
- end
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
- gem "foo", :git => "#{lib_path("foo-1.0")}"
- G
-
- bundle "config set auto_install 1"
- bundle "exec foo"
- expect(out).to include("Fetching myrack 0.9.1")
- expect(out).to include("Fetching #{lib_path("foo-1.0")}")
- expect(out.lines).to end_with("1.0")
- end
-
it "loads the correct optparse when `auto_install` is set, and optparse is a dependency" do
- if Gem.rubygems_version < Gem::Version.new("3.3.0.a")
+ if Gem.ruby_version >= Gem::Version.new("3.0.0") && Gem.rubygems_version < Gem::Version.new("3.3.0.a")
skip "optparse is a default gem, and rubygems loads it during install"
end
@@ -630,13 +630,13 @@ RSpec.describe "bundle exec" do
build_gem "optparse", "999.999.999"
end
- system_gems "optparse-999.999.998", gem_repo: gem_repo4
+ system_gems "optparse-999.999.998", :gem_repo => gem_repo4
bundle "config set auto_install 1"
bundle "config set --local path vendor/bundle"
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "fastlane"
G
@@ -657,20 +657,19 @@ RSpec.describe "bundle exec" do
s.version = '1.0'
s.summary = 'TODO: Add summary'
s.authors = 'Me'
- s.rubygems_version = nil
end
G
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
- bundle "exec irb", raise_on_error: false
+ bundle "exec irb", :raise_on_error => false
expect(err).to match("The gemspec at #{lib_path("foo-1.0").join("foo.gemspec")} is not valid")
- expect(err).to match(/missing value for attribute rubygems_version|rubygems_version must not be nil/)
+ expect(err).to match('"TODO" is not a summary')
end
end
@@ -679,7 +678,7 @@ RSpec.describe "bundle exec" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
module Monkey
def bin_path(a,b,c)
@@ -690,69 +689,50 @@ RSpec.describe "bundle exec" do
G
bundle "config set path.system true"
bundle "install"
- bundle "exec ruby -e '`bundle -v`; puts $?.success?'", env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ bundle "exec ruby -e '`bundle -v`; puts $?.success?'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
expect(out).to match("true")
end
end
- describe "bundle exec gem uninstall" do
- before do
- build_repo4 do
- build_gem "foo"
- end
-
- install_gemfile <<-G
- source "https://gem.repo4"
-
- gem "foo"
- G
- end
-
- it "works" do
- bundle "exec #{gem_cmd} uninstall foo"
- expect(out).to eq("Successfully uninstalled foo-1.0")
- end
- end
-
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 "myrack"
+ require "rack"
puts "EXEC: \#{caller.grep(/load/).empty? ? 'exec' : 'load'}"
puts "ARGS: \#{$0} \#{ARGV.join(' ')}"
- puts "MYRACK: \#{MYRACK}"
+ puts "RACK: \#{RACK}"
process_title = `ps -o args -p \#{Process.pid}`.split("\n", 2).last.strip
puts "PROCESS: \#{process_title}"
RUBY
before do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
bundled_app(path).open("w") {|f| f << executable }
bundled_app(path).chmod(0o755)
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
let(:exec) { "EXEC: load" }
let(:args) { "ARGS: #{path} arg1 arg2" }
- let(:myrack) { "MYRACK: 1.0.0" }
+ let(:rack) { "RACK: 1.0.0" }
let(:process) do
title = "PROCESS: #{path}"
title += " arg1 arg2"
title
end
let(:exit_code) { 0 }
- let(:expected) { [exec, args, myrack, process].join("\n") }
+ let(:expected) { [exec, args, rack, process].join("\n") }
let(:expected_err) { "" }
- subject { bundle "exec #{path} arg1 arg2", raise_on_error: false }
+ subject { bundle "exec #{path} arg1 arg2", :raise_on_error => false }
it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
@@ -834,7 +814,8 @@ RSpec.describe "bundle exec" do
let(:executable) { super() << "\nraise 'ERROR'" }
let(:exit_code) { 1 }
let(:expected_err) do
- /\Abundler: failed to load command: #{Regexp.quote(path.to_s)} \(#{Regexp.quote(path.to_s)}\)\n#{Regexp.quote(path.to_s)}:10:in [`']<top \(required\)>': ERROR \(RuntimeError\)/
+ "bundler: failed to load command: #{path} (#{path})" \
+ "\n#{path}:10:in `<top (required)>': ERROR (RuntimeError)"
end
it "runs like a normally executed executable" do
@@ -842,7 +823,7 @@ RSpec.describe "bundle exec" do
subject
expect(exitstatus).to eq(exit_code)
- expect(err).to match(expected_err)
+ expect(err).to start_with(expected_err)
expect(out).to eq(expected)
end
end
@@ -876,11 +857,11 @@ RSpec.describe "bundle exec" do
end
end
- context "when Bundler.setup fails", bundler: "< 3" do
+ context "when Bundler.setup fails", :bundler => "< 3" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', '2'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', '2'
G
ENV["BUNDLER_FORCE_TTY"] = "true"
end
@@ -888,11 +869,11 @@ RSpec.describe "bundle exec" do
let(:exit_code) { Bundler::GemNotFound.new.status_code }
let(:expected) { "" }
let(:expected_err) { <<-EOS.strip }
-Could not find gem 'myrack (= 2)' in locally installed gems.
+Could not find gem 'rack (= 2)' in locally installed gems.
-The source contains the following gems matching 'myrack':
- * myrack-0.9.1
- * myrack-1.0.0
+The source contains the following gems matching 'rack':
+ * rack-0.9.1
+ * rack-1.0.0
Run `bundle install` to install missing gems.
EOS
@@ -906,11 +887,11 @@ Run `bundle install` to install missing gems.
end
end
- context "when Bundler.setup fails", bundler: "3" do
+ context "when Bundler.setup fails", :bundler => "3" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', '2'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', '2'
G
ENV["BUNDLER_FORCE_TTY"] = "true"
end
@@ -918,10 +899,10 @@ Run `bundle install` to install missing gems.
let(:exit_code) { Bundler::GemNotFound.new.status_code }
let(:expected) { "" }
let(:expected_err) { <<-EOS.strip }
-Could not find gem 'myrack (= 2)' in locally installed gems.
+Could not find gem 'rack (= 2)' in locally installed gems.
-The source contains the following gems matching 'myrack':
- * myrack-1.0.0
+The source contains the following gems matching 'rack':
+ * rack-1.0.0
Run `bundle install` to install missing gems.
EOS
@@ -935,30 +916,6 @@ Run `bundle install` to install missing gems.
end
end
- context "when Bundler.setup fails and Gemfile is not the default" do
- before do
- gemfile "CustomGemfile", <<-G
- source "https://gem.repo1"
- gem 'myrack', '2'
- G
- ENV["BUNDLER_FORCE_TTY"] = "true"
- ENV["BUNDLE_GEMFILE"] = "CustomGemfile"
- ENV["BUNDLER_ORIG_BUNDLE_GEMFILE"] = nil
- end
-
- let(:exit_code) { Bundler::GemNotFound.new.status_code }
- let(:expected) { "" }
-
- it "prints proper suggestion" do
- skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
-
- subject
- expect(exitstatus).to eq(exit_code)
- expect(err).to include("Run `bundle install --gemfile CustomGemfile` to install missing gems.")
- expect(out).to eq(expected)
- end
- end
-
context "when the executable exits non-zero via at_exit" do
let(:executable) { super() + "\n\nat_exit { $! ? raise($!) : exit(1) }" }
let(:exit_code) { 1 }
@@ -1043,7 +1000,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
@@ -1070,7 +1027,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}
@@ -1101,8 +1058,8 @@ __FILE__: #{path.to_s.inspect}
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set path vendor/bundler"
bundle :install
@@ -1115,7 +1072,7 @@ __FILE__: #{path.to_s.inspect}
puts `bundle exec echo foo`
RUBY
file.chmod(0o777)
- bundle "exec #{file}", env: { "PATH" => path }
+ bundle "exec #{file}", :env => { "PATH" => path }
expect(out).to eq("foo")
end
end
@@ -1124,7 +1081,7 @@ __FILE__: #{path.to_s.inspect}
before do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
- install_gemfile "source \"https://gem.repo1\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
end
it "does not undo the monkeypatches" do
@@ -1174,18 +1131,18 @@ __FILE__: #{path.to_s.inspect}
end
bundle "config set path vendor/bundle"
- bundle "config set gemfile gemfiles/myrack_6_1.gemfile"
+ bundle "config set gemfile gemfiles/rack_6_1.gemfile"
- gemfile(bundled_app("gemfiles/myrack_6_1.gemfile"), <<~RUBY)
- source "https://gem.repo2"
+ create_file(bundled_app("gemfiles/rack_6_1.gemfile"), <<~RUBY)
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "6.1.0"
RUBY
# A Gemfile needs to be in the root to trick bundler's root resolution
- gemfile "source 'https://gem.repo1'"
+ create_file(bundled_app("Gemfile"), "source \"#{file_uri_for(gem_repo1)}\"")
- bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle "install"
end
it "can still find gems after a nested subprocess" do
@@ -1208,13 +1165,13 @@ __FILE__: #{path.to_s.inspect}
context "with a system gem that shadows a default gem" do
let(:openssl_version) { "99.9.9" }
- let(:expected) { ruby "gem 'openssl', '< 999999'; require 'openssl'; puts OpenSSL::VERSION", artifice: nil, raise_on_error: false }
+ let(:expected) { ruby "gem 'openssl', '< 999999'; require 'openssl'; puts OpenSSL::VERSION", :artifice => nil, :raise_on_error => false }
it "only leaves the default gem in the stdlib available" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
skip "openssl isn't a default gem" if expected.empty?
- install_gemfile "source \"https://gem.repo1\"" # must happen before installing the broken system gem
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"" # must happen before installing the broken system gem
build_repo4 do
build_gem "openssl", openssl_version do |s|
@@ -1224,7 +1181,7 @@ __FILE__: #{path.to_s.inspect}
end
end
- system_gems("openssl-#{openssl_version}", gem_repo: gem_repo4)
+ system_gems("openssl-#{openssl_version}", :gem_repo => gem_repo4)
file = bundled_app("require_openssl.rb")
create_file(file, <<-RUBY)
@@ -1237,15 +1194,15 @@ __FILE__: #{path.to_s.inspect}
env = { "PATH" => path }
aggregate_failures do
- expect(bundle("exec #{file}", artifice: nil, env: env)).to eq(expected)
- expect(bundle("exec bundle exec #{file}", artifice: nil, env: env)).to eq(expected)
- expect(bundle("exec ruby #{file}", artifice: nil, env: env)).to eq(expected)
- expect(run(file.read, artifice: nil, env: env)).to eq(expected)
+ expect(bundle("exec #{file}", :artifice => nil, :env => env)).to eq(expected)
+ expect(bundle("exec bundle exec #{file}", :artifice => nil, :env => env)).to eq(expected)
+ expect(bundle("exec ruby #{file}", :artifice => nil, :env => env)).to eq(expected)
+ expect(run(file.read, :artifice => nil, :env => env)).to eq(expected)
end
skip "ruby_core has openssl and rubygems in the same folder, and this test needs rubygems require but default openssl not in a directly added entry in $LOAD_PATH" if ruby_core?
# sanity check that we get the newer, custom version without bundler
- sys_exec "#{Gem.ruby} #{file}", env: env, raise_on_error: false
+ sys_exec "#{Gem.ruby} #{file}", :env => env, :raise_on_error => false
expect(err).to include("custom openssl should not be loaded")
end
end
@@ -1255,7 +1212,7 @@ __FILE__: #{path.to_s.inspect}
build_git "simple_git_binary", &:add_c_extension
bundle "config set --local path .bundle"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "simple_git_binary", :git => '#{lib_path("simple_git_binary-1.0")}'
G
end
diff --git a/spec/bundler/commands/fund_spec.rb b/spec/bundler/commands/fund_spec.rb
index 6f4e61da30..5415b88eeb 100644
--- a/spec/bundler/commands/fund_spec.rb
+++ b/spec/bundler/commands/fund_spec.rb
@@ -30,22 +30,22 @@ RSpec.describe "bundle fund" do
it "prints fund information for all gems in the bundle" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata'
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
bundle "fund"
expect(out).to include("* has_funding_and_other_metadata (1.0)\n Funding: https://example.com/has_funding_and_other_metadata/funding")
expect(out).to include("* has_funding (1.2.3)\n Funding: https://example.com/has_funding/funding")
- expect(out).to_not include("myrack-obama")
+ expect(out).to_not include("rack-obama")
end
it "does not consider fund information for gem dependencies" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'gem_with_dependent_funding'
G
@@ -55,46 +55,10 @@ RSpec.describe "bundle fund" do
expect(out).to_not include("gem_with_dependent_funding")
end
- it "does not consider fund information for uninstalled optional dependencies" do
- install_gemfile <<-G
- source "https://gem.repo2"
- group :whatever, optional: true do
- gem 'has_funding_and_other_metadata'
- end
- gem 'has_funding'
- gem 'myrack-obama'
- G
-
- bundle "fund"
-
- expect(out).to include("* has_funding (1.2.3)\n Funding: https://example.com/has_funding/funding")
- expect(out).to_not include("has_funding_and_other_metadata")
- expect(out).to_not include("myrack-obama")
- end
-
- it "considers fund information for installed optional dependencies" do
- bundle "config set with whatever"
-
- install_gemfile <<-G
- source "https://gem.repo2"
- group :whatever, optional: true do
- gem 'has_funding_and_other_metadata'
- end
- gem 'has_funding'
- gem 'myrack-obama'
- G
-
- bundle "fund"
-
- expect(out).to include("* has_funding_and_other_metadata (1.0)\n Funding: https://example.com/has_funding_and_other_metadata/funding")
- expect(out).to include("* has_funding (1.2.3)\n Funding: https://example.com/has_funding/funding")
- expect(out).to_not include("myrack-obama")
- end
-
it "prints message if none of the gems have fund information" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack-obama'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack-obama'
G
bundle "fund"
@@ -105,7 +69,7 @@ RSpec.describe "bundle fund" do
describe "with --group option" do
it "prints fund message for only specified group gems" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata', :group => :development
gem 'has_funding'
G
diff --git a/spec/bundler/commands/help_spec.rb b/spec/bundler/commands/help_spec.rb
index 0c7031e813..409c49f9e1 100644
--- a/spec/bundler/commands/help_spec.rb
+++ b/spec/bundler/commands/help_spec.rb
@@ -15,13 +15,6 @@ RSpec.describe "bundle help" do
expect(out).to eq(%(["#{man_dir}/bundle-install.1"]))
end
- it "prexifes bundle commands with bundle- and resolves aliases when finding the man files" do
- with_fake_man do
- bundle "help package"
- end
- expect(out).to eq(%(["#{man_dir}/bundle-cache.1"]))
- end
-
it "simply outputs the human readable file when there is no man on the path" do
with_path_as("") do
bundle "help install"
@@ -78,7 +71,7 @@ RSpec.describe "bundle help" do
it "has helpful output when using --help flag for a non-existent command" do
with_fake_man do
- bundle "instill -h", raise_on_error: false
+ bundle "instill -h", :raise_on_error => false
end
expect(err).to include('Could not find command "instill".')
end
diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb
index 42f288a1d8..2e17ee6dd8 100644
--- a/spec/bundler/commands/info_spec.rb
+++ b/spec/bundler/commands/info_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe "bundle info" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
gem "has_metadata"
gem "thin"
@@ -65,7 +65,7 @@ RSpec.describe "bundle info" do
end
it "complains if gem not in bundle" do
- bundle "info missing", raise_on_error: false
+ bundle "info missing", :raise_on_error => false
expect(err).to eq("Could not find gem 'missing'.")
end
@@ -74,16 +74,16 @@ RSpec.describe "bundle info" do
bundle "info rails --path"
- expect(err).to include("The gem rails has been deleted.")
- expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
+ expect(err).to match(/The gem rails has been deleted/i)
+ expect(err).to match(default_bundle_path("gems", "rails-2.3.2").to_s)
bundle "info rail --path"
- expect(err).to include("The gem rails has been deleted.")
- expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
+ expect(err).to match(/The gem rails has been deleted/i)
+ expect(err).to match(default_bundle_path("gems", "rails-2.3.2").to_s)
bundle "info rails"
- expect(err).to include("The gem rails has been deleted.")
- expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
+ expect(err).to match(/The gem rails has been deleted/i)
+ expect(err).to match(default_bundle_path("gems", "rails-2.3.2").to_s)
end
context "given a default gem shippped in ruby", :ruby_repo do
@@ -127,9 +127,9 @@ RSpec.describe "bundle info" do
context "when gem has a reverse dependency on any version" do
it "prints the details" do
- bundle "info myrack"
+ bundle "info rack"
- expect(out).to include("Reverse Dependencies: \n\t\tthin (1.0) depends on myrack (>= 0)")
+ expect(out).to include("Reverse Dependencies: \n\t\tthin (1.0) depends on rack (>= 0)")
end
end
@@ -157,7 +157,7 @@ RSpec.describe "bundle info" do
it "prints out git info" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
expect(the_bundle).to include_gems "foo 1.0"
@@ -167,13 +167,13 @@ RSpec.describe "bundle info" do
end
it "prints out branch names other than main" do
- update_git "foo", branch: "omg" do |s|
+ update_git "foo", :branch => "omg" do |s|
s.write "lib/foo.rb", "FOO = '1.0.omg'"
end
@revision = revision_for(lib_path("foo-1.0"))[0...6]
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "omg"
G
expect(the_bundle).to include_gems "foo 1.0.omg"
@@ -185,7 +185,7 @@ RSpec.describe "bundle info" do
it "doesn't print the branch when tied to a ref" do
sha = revision_for(lib_path("foo-1.0"))
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "#{sha}"
G
@@ -194,9 +194,9 @@ RSpec.describe "bundle info" do
end
it "handles when a version is a '-' prerelease" do
- @git = build_git("foo", "1.0.0-beta.1", path: lib_path("foo"))
+ @git = build_git("foo", "1.0.0-beta.1", :path => lib_path("foo"))
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0.0-beta.1", :git => "#{lib_path("foo")}"
G
expect(the_bundle).to include_gems "foo 1.0.0.pre.beta.1"
@@ -209,26 +209,26 @@ RSpec.describe "bundle info" do
context "with a valid regexp for gem name" do
it "presents alternatives", :readline do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
bundle "info rac"
- expect(out).to match(/\A1 : myrack\n2 : myrack-obama\n0 : - exit -(\n>|\z)/)
+ expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>)?\z/)
end
end
context "with an invalid regexp for gem name" do
it "does not find the gem" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
invalid_regexp = "[]"
- bundle "info #{invalid_regexp}", raise_on_error: false
+ bundle "info #{invalid_regexp}", :raise_on_error => false
expect(err).to include("Could not find gem '#{invalid_regexp}'.")
end
end
@@ -238,11 +238,11 @@ RSpec.describe "bundle info" do
bundle "config without test"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails", group: :test
G
- bundle "info rails", raise_on_error: false
+ bundle "info rails", :raise_on_error => false
expect(err).to include("Could not find gem 'rails', because it's in the group 'test', configured to be ignored.")
end
end
diff --git a/spec/bundler/commands/init_spec.rb b/spec/bundler/commands/init_spec.rb
index 538e61fd47..9c499b99a1 100644
--- a/spec/bundler/commands/init_spec.rb
+++ b/spec/bundler/commands/init_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe "bundle init" do
it "honours the current process umask when generating from a template" do
FileUtils.mkdir(target_dir)
- bundle :init, dir: target_dir
+ bundle :init, :dir => target_dir
generated_mode = File.stat(File.join(target_dir, "Gemfile")).mode & 0o111
expect(generated_mode).to be_zero
end
@@ -32,17 +32,17 @@ RSpec.describe "bundle init" do
context "when a Gemfile already exists" do
before do
- gemfile <<-G
+ create_file "Gemfile", <<-G
gem "rails"
G
end
it "does not change existing Gemfiles" do
- expect { bundle :init, raise_on_error: false }.not_to change { File.read(bundled_app_gemfile) }
+ expect { bundle :init, :raise_on_error => false }.not_to change { File.read(bundled_app_gemfile) }
end
it "notifies the user that an existing Gemfile already exists" do
- bundle :init, raise_on_error: false
+ bundle :init, :raise_on_error => false
expect(err).to include("Gemfile already exists")
end
end
@@ -55,7 +55,7 @@ RSpec.describe "bundle init" do
FileUtils.mkdir bundled_app(subdir)
- bundle :init, dir: bundled_app(subdir)
+ bundle :init, :dir => bundled_app(subdir)
expect(out).to include("Writing new Gemfile")
expect(bundled_app("#{subdir}/Gemfile")).to be_file
@@ -71,7 +71,7 @@ RSpec.describe "bundle init" do
mode = File.stat(bundled_app(subdir)).mode ^ 0o222
FileUtils.chmod mode, bundled_app(subdir)
- bundle :init, dir: bundled_app(subdir), raise_on_error: false
+ bundle :init, :dir => bundled_app(subdir), :raise_on_error => false
expect(err).to include("directory is not writable")
expect(Dir[bundled_app("#{subdir}/*")]).to be_empty
@@ -79,24 +79,24 @@ RSpec.describe "bundle init" do
end
context "given --gemspec option" do
- let(:spec_file) { tmp("test.gemspec") }
+ let(:spec_file) { tmp.join("test.gemspec") }
it "should generate from an existing gemspec" do
File.open(spec_file, "w") do |file|
file << <<-S
Gem::Specification.new do |s|
s.name = 'test'
- s.add_dependency 'myrack', '= 1.0.1'
+ s.add_dependency 'rack', '= 1.0.1'
s.add_development_dependency 'rspec', '1.2'
end
S
end
- bundle :init, gemspec: spec_file
+ bundle :init, :gemspec => spec_file
gemfile = bundled_app_gemfile.read
expect(gemfile).to match(%r{source 'https://rubygems.org'})
- expect(gemfile.scan(/gem "myrack", "= 1.0.1"/).size).to eq(1)
+ expect(gemfile.scan(/gem "rack", "= 1.0.1"/).size).to eq(1)
expect(gemfile.scan(/gem "rspec", "= 1.2"/).size).to eq(1)
expect(gemfile.scan(/group :development/).size).to eq(1)
end
@@ -112,7 +112,7 @@ RSpec.describe "bundle init" do
S
end
- bundle :init, gemspec: spec_file, raise_on_error: false
+ bundle :init, :gemspec => spec_file, :raise_on_error => false
expect(err).to include("There was an error while loading `test.gemspec`")
end
end
@@ -129,17 +129,17 @@ RSpec.describe "bundle init" do
context "when gems.rb already exists" do
before do
- gemfile("gems.rb", <<-G)
+ create_file("gems.rb", <<-G)
gem "rails"
G
end
it "does not change existing Gemfiles" do
- expect { bundle :init, raise_on_error: false }.not_to change { File.read(bundled_app("gems.rb")) }
+ expect { bundle :init, :raise_on_error => false }.not_to change { File.read(bundled_app("gems.rb")) }
end
it "notifies the user that an existing gems.rb already exists" do
- bundle :init, raise_on_error: false
+ bundle :init, :raise_on_error => false
expect(err).to include("gems.rb already exists")
end
end
@@ -152,7 +152,7 @@ RSpec.describe "bundle init" do
FileUtils.mkdir bundled_app(subdir)
- bundle :init, dir: bundled_app(subdir)
+ bundle :init, :dir => bundled_app(subdir)
expect(out).to include("Writing new gems.rb")
expect(bundled_app("#{subdir}/gems.rb")).to be_file
@@ -160,14 +160,14 @@ RSpec.describe "bundle init" do
end
context "given --gemspec option" do
- let(:spec_file) { tmp("test.gemspec") }
+ let(:spec_file) { tmp.join("test.gemspec") }
before do
File.open(spec_file, "w") do |file|
file << <<-S
Gem::Specification.new do |s|
s.name = 'test'
- s.add_dependency 'myrack', '= 1.0.1'
+ s.add_dependency 'rack', '= 1.0.1'
s.add_development_dependency 'rspec', '1.2'
end
S
@@ -175,33 +175,20 @@ RSpec.describe "bundle init" do
end
it "should generate from an existing gemspec" do
- bundle :init, gemspec: spec_file
+ bundle :init, :gemspec => spec_file
gemfile = bundled_app("gems.rb").read
expect(gemfile).to match(%r{source 'https://rubygems.org'})
- expect(gemfile.scan(/gem "myrack", "= 1.0.1"/).size).to eq(1)
+ expect(gemfile.scan(/gem "rack", "= 1.0.1"/).size).to eq(1)
expect(gemfile.scan(/gem "rspec", "= 1.2"/).size).to eq(1)
expect(gemfile.scan(/group :development/).size).to eq(1)
end
it "prints message to user" do
- bundle :init, gemspec: spec_file
+ bundle :init, :gemspec => spec_file
expect(out).to include("Writing new gems.rb")
end
end
end
-
- describe "using the --gemfile" do
- it "should use the --gemfile value to name the gemfile" do
- custom_gemfile_name = "NiceGemfileName"
-
- bundle :init, gemfile: custom_gemfile_name
-
- expect(out).to include("Writing new #{custom_gemfile_name}")
- used_template = File.read("#{source_root}/lib/bundler/templates/Gemfile")
- generated_gemfile = bundled_app(custom_gemfile_name).read
- expect(generated_gemfile).to eq(used_template)
- end
- end
end
diff --git a/spec/bundler/commands/inject_spec.rb b/spec/bundler/commands/inject_spec.rb
index 193806a02a..92e86bd6cc 100644
--- a/spec/bundler/commands/inject_spec.rb
+++ b/spec/bundler/commands/inject_spec.rb
@@ -1,18 +1,18 @@
# frozen_string_literal: true
-RSpec.describe "bundle inject", bundler: "< 3" do
+RSpec.describe "bundle inject", :bundler => "< 3" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
context "without a lockfile" do
it "locks with the injected gems" do
expect(bundled_app_lock).not_to exist
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_lock.read).to match(/myrack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_lock.read).to match(/rack-obama/)
end
end
@@ -22,28 +22,28 @@ RSpec.describe "bundle inject", bundler: "< 3" do
end
it "adds the injected gems to the Gemfile" do
- expect(bundled_app_gemfile.read).not_to match(/myrack-obama/)
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_gemfile.read).to match(/myrack-obama/)
+ expect(bundled_app_gemfile.read).not_to match(/rack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_gemfile.read).to match(/rack-obama/)
end
it "locks with the injected gems" do
- expect(bundled_app_lock.read).not_to match(/myrack-obama/)
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_lock.read).to match(/myrack-obama/)
+ expect(bundled_app_lock.read).not_to match(/rack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_lock.read).to match(/rack-obama/)
end
end
context "with injected gems already in the Gemfile" do
it "doesn't add existing gems" do
- bundle "inject 'myrack' '> 0'", raise_on_error: false
+ bundle "inject 'rack' '> 0'", :raise_on_error => false
expect(err).to match(/cannot specify the same gem twice/i)
end
end
context "incorrect arguments" do
it "fails when more than 2 arguments are passed" do
- bundle "inject gem_name 1 v", raise_on_error: false
+ bundle "inject gem_name 1 v", :raise_on_error => false
expect(err).to eq(<<-E.strip)
ERROR: "bundle inject" was called with arguments ["gem_name", "1", "v"]
Usage: "bundle inject GEM VERSION"
@@ -53,25 +53,25 @@ Usage: "bundle inject GEM VERSION"
context "with source option" do
it "add gem with source option in gemfile" do
- bundle "inject 'foo' '>0' --source https://gem.repo1"
+ bundle "inject 'foo' '>0' --source #{file_uri_for(gem_repo1)}"
gemfile = bundled_app_gemfile.read
- str = "gem \"foo\", \"> 0\", :source => \"https://gem.repo1\""
+ str = "gem \"foo\", \"> 0\", :source => \"#{file_uri_for(gem_repo1)}\""
expect(gemfile).to include str
end
end
context "with group option" do
it "add gem with group option in gemfile" do
- bundle "inject 'myrack-obama' '>0' --group=development"
+ bundle "inject 'rack-obama' '>0' --group=development"
gemfile = bundled_app_gemfile.read
- str = "gem \"myrack-obama\", \"> 0\", :group => :development"
+ str = "gem \"rack-obama\", \"> 0\", :group => :development"
expect(gemfile).to include str
end
it "add gem with multiple groups in gemfile" do
- bundle "inject 'myrack-obama' '>0' --group=development,test"
+ bundle "inject 'rack-obama' '>0' --group=development,test"
gemfile = bundled_app_gemfile.read
- str = "gem \"myrack-obama\", \"> 0\", :groups => [:development, :test]"
+ str = "gem \"rack-obama\", \"> 0\", :groups => [:development, :test]"
expect(gemfile).to include str
end
end
@@ -87,31 +87,31 @@ Usage: "bundle inject GEM VERSION"
end
it "injects anyway" do
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_gemfile.read).to match(/myrack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_gemfile.read).to match(/rack-obama/)
end
it "locks with the injected gems" do
- expect(bundled_app_lock.read).not_to match(/myrack-obama/)
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_lock.read).to match(/myrack-obama/)
+ expect(bundled_app_lock.read).not_to match(/rack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_lock.read).to match(/rack-obama/)
end
it "restores frozen afterwards" do
- bundle "inject 'myrack-obama' '> 0'"
+ bundle "inject 'rack-obama' '> 0'"
config = Psych.load(bundled_app(".bundle/config").read)
expect(config["BUNDLE_DEPLOYMENT"] || config["BUNDLE_FROZEN"]).to eq("true")
end
it "doesn't allow Gemfile changes" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack-obama"
G
- bundle "inject 'myrack' '> 0'", raise_on_error: false
- expect(err).to match(/the lockfile can't be updated because frozen mode is set/)
+ bundle "inject 'rack' '> 0'", :raise_on_error => false
+ expect(err).to match(/trying to install in deployment mode after changing/)
- expect(bundled_app_lock.read).not_to match(/myrack-obama/)
+ expect(bundled_app_lock.read).not_to match(/rack-obama/)
end
end
end
diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb
index 19711045c2..f572bdf176 100644
--- a/spec/bundler/commands/install_spec.rb
+++ b/spec/bundler/commands/install_spec.rb
@@ -4,7 +4,7 @@ RSpec.describe "bundle install with gem sources" do
describe "the simple case" do
it "prints output and returns if no dependencies are specified" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
bundle :install
@@ -12,7 +12,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "does not make a lockfile if the install fails" do
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
raise StandardError, "FAIL"
G
@@ -22,17 +22,17 @@ RSpec.describe "bundle install with gem sources" do
it "creates a Gemfile.lock" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect(bundled_app_lock).to exist
end
- it "does not create ./.bundle by default", bundler: "< 3" do
+ it "does not create ./.bundle by default", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :install # can't use install_gemfile since it sets retry
@@ -41,18 +41,18 @@ RSpec.describe "bundle install with gem sources" do
it "does not create ./.bundle by default when installing to system gems" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle :install, env: { "BUNDLE_PATH__SYSTEM" => "true" } # can't use install_gemfile since it sets retry
+ bundle :install, :env => { "BUNDLE_PATH__SYSTEM" => "true" } # can't use install_gemfile since it sets retry
expect(bundled_app(".bundle")).not_to exist
end
it "creates lock files based on the Gemfile name" do
gemfile bundled_app("OmgFile"), <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0"
G
bundle "install --gemfile OmgFile"
@@ -62,13 +62,13 @@ RSpec.describe "bundle install with gem sources" do
it "doesn't delete the lockfile if one already exists" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
lockfile = File.read(bundled_app_lock)
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
raise StandardError, "FAIL"
G
@@ -77,8 +77,8 @@ RSpec.describe "bundle install with gem sources" do
it "does not touch the lockfile if nothing changed" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect { run "1" }.not_to change { File.mtime(bundled_app_lock) }
@@ -86,60 +86,60 @@ RSpec.describe "bundle install with gem sources" do
it "fetches gems" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- expect(default_bundle_path("gems/myrack-1.0.0")).to exist
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(default_bundle_path("gems/rack-1.0.0")).to exist
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "auto-heals missing gems" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- FileUtils.rm_rf(default_bundle_path("gems/myrack-1.0.0"))
+ FileUtils.rm_rf(default_bundle_path("gems/rack-1.0.0"))
bundle "install --verbose"
- expect(out).to include("Installing myrack 1.0.0")
- expect(default_bundle_path("gems/myrack-1.0.0")).to exist
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(out).to include("Installing rack 1.0.0")
+ expect(default_bundle_path("gems/rack-1.0.0")).to exist
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "fetches gems when multiple versions are specified" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', "> 0.9", "< 1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', "> 0.9", "< 1.0"
G
- expect(default_bundle_path("gems/myrack-0.9.1")).to exist
- expect(the_bundle).to include_gems("myrack 0.9.1")
+ expect(default_bundle_path("gems/rack-0.9.1")).to exist
+ expect(the_bundle).to include_gems("rack 0.9.1")
end
it "fetches gems when multiple versions are specified take 2" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', "< 1.0", "> 0.9"
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', "< 1.0", "> 0.9"
G
- expect(default_bundle_path("gems/myrack-0.9.1")).to exist
- expect(the_bundle).to include_gems("myrack 0.9.1")
+ expect(default_bundle_path("gems/rack-0.9.1")).to exist
+ expect(the_bundle).to include_gems("rack 0.9.1")
end
it "raises an appropriate error when gems are specified using symbols" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem :myrack
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem :rack
G
expect(exitstatus).to eq(4)
end
it "pulls in dependencies" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
@@ -148,11 +148,11 @@ RSpec.describe "bundle install with gem sources" do
it "does the right version" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- expect(the_bundle).to include_gems "myrack 0.9.1"
+ expect(the_bundle).to include_gems "rack 0.9.1"
end
it "does not install the development dependency" do
@@ -163,7 +163,7 @@ RSpec.describe "bundle install with gem sources" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "with_development_dependency"
G
@@ -173,7 +173,7 @@ RSpec.describe "bundle install with gem sources" do
it "resolves correctly" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activemerchant"
gem "rails"
G
@@ -183,12 +183,12 @@ RSpec.describe "bundle install with gem sources" do
it "activates gem correctly according to the resolved gems" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", "2.3.5"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activemerchant"
gem "rails"
G
@@ -197,7 +197,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "does not reinstall any gem that is already available locally" do
- system_gems "activesupport-2.3.2", path: default_bundle_path
+ system_gems "activesupport-2.3.2", :path => default_bundle_path
build_repo2 do
build_gem "activesupport", "2.3.2" do |s|
@@ -206,7 +206,7 @@ RSpec.describe "bundle install with gem sources" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activerecord", "2.3.2"
G
@@ -214,34 +214,36 @@ RSpec.describe "bundle install with gem sources" do
end
it "works when the gemfile specifies gems that only exist in the system" do
- build_gem "foo", to_bundle: true
+ build_gem "foo", :to_bundle => true
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "foo"
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "foo 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "foo 1.0.0"
end
it "prioritizes local gems over remote gems" do
- build_gem "myrack", "9.0.0", to_bundle: true
+ build_gem "rack", "1.0.0", :to_bundle => true do |s|
+ s.add_dependency "activesupport", "2.3.5"
+ end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 9.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5"
end
it "loads env plugins" do
plugin_msg = "hello from an env plugin!"
create_file "plugins/rubygems_plugin.rb", "puts '#{plugin_msg}'"
rubylib = ENV["RUBYLIB"].to_s.split(File::PATH_SEPARATOR).unshift(bundled_app("plugins").to_s).join(File::PATH_SEPARATOR)
- install_gemfile <<-G, env: { "RUBYLIB" => rubylib }
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :env => { "RUBYLIB" => rubylib }
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect(last_command.stdboth).to include(plugin_msg)
@@ -249,100 +251,102 @@ RSpec.describe "bundle install with gem sources" do
describe "with a gem that installs multiple platforms" do
it "installs gems for the local platform as first choice" do
- simulate_platform "x86-darwin-100" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
+ skip "version is 1.0, not 1.0.0" if Gem.win_platform?
- expect(the_bundle).to include_gems("platform_specific 1.0 x86-darwin-100")
- end
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
+
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0.0 #{Bundler.local_platform}")
end
it "falls back on plain ruby" do
- simulate_platform "foo-bar-baz" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
+ simulate_platform "foo-bar-baz"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
- expect(the_bundle).to include_gems("platform_specific 1.0 ruby")
- end
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0.0 RUBY")
end
it "installs gems for java" do
- simulate_platform "java" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
+ simulate_platform "java"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
- expect(the_bundle).to include_gems("platform_specific 1.0 java")
- end
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0.0 JAVA")
end
it "installs gems for windows" do
- simulate_platform x86_mswin32 do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
+ simulate_platform x86_mswin32
- expect(the_bundle).to include_gems("platform_specific 1.0 x86-mswin32")
- end
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
+
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0 x86-mswin32")
end
end
describe "doing bundle install foo" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
it "works" do
bundle "config set --local path vendor"
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
- it "allows running bundle install --system without deleting foo", bundler: "< 3" do
+ it "allows running bundle install --system without deleting foo", :bundler => "< 3" do
bundle "install --path vendor"
bundle "install --system"
FileUtils.rm_rf(bundled_app("vendor"))
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
- it "allows running bundle install --system after deleting foo", bundler: "< 3" do
+ it "allows running bundle install --system after deleting foo", :bundler => "< 3" do
bundle "install --path vendor"
FileUtils.rm_rf(bundled_app("vendor"))
bundle "install --system"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
- it "finds gems in multiple sources", bundler: "< 3" do
+ it "finds gems in multiple sources", :bundler => "< 3" do
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
- install_gemfile <<-G, artifice: "compact_index_extra"
- source "https://gemserver.test"
- source "https://gemserver.test/extra"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "1.2.3"
- gem "myrack", "1.2"
+ gem "rack", "1.2"
G
- expect(the_bundle).to include_gems "myrack 1.2", "activesupport 1.2.3"
+ expect(the_bundle).to include_gems "rack 1.2", "activesupport 1.2.3"
end
it "gives a useful error if no sources are set" do
- install_gemfile <<-G, raise_on_error: false
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ gem "rack"
G
expect(err).to include("This Gemfile does not include an explicit global source. " \
@@ -353,7 +357,7 @@ RSpec.describe "bundle install with gem sources" do
it "creates a Gemfile.lock on a blank Gemfile" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
expect(File.exist?(bundled_app_lock)).to eq(true)
@@ -363,12 +367,12 @@ RSpec.describe "bundle install with gem sources" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
+ gem "rack"
G
- expect(err).to include("Your Gemfile lists the gem myrack (>= 0) more than once.")
+ expect(err).to include("Your Gemfile lists the gem rack (>= 0) more than once.")
expect(err).to include("Remove any duplicate entries and specify the gem only once.")
expect(err).to include("While it's not a problem now, it could cause errors if you change the version of one of them later.")
end
@@ -377,12 +381,12 @@ RSpec.describe "bundle install with gem sources" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "1.0"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "1.0"
+ gem "rack", "1.0"
G
- expect(err).to include("Your Gemfile lists the gem myrack (= 1.0) more than once.")
+ expect(err).to include("Your Gemfile lists the gem rack (= 1.0) more than once.")
expect(err).to include("Remove any duplicate entries and specify the gem only once.")
expect(err).to include("While it's not a problem now, it could cause errors if you change the version of one of them later.")
end
@@ -391,20 +395,20 @@ RSpec.describe "bundle install with gem sources" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", :platform => :jruby
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", :platform => :jruby
+ gem "rack"
G
bundle "install"
- expect(err).to include("Your Gemfile lists the gem myrack (>= 0) more than once.")
+ expect(err).to include("Your Gemfile lists the gem rack (>= 0) more than once.")
expect(err).to include("Remove any duplicate entries and specify the gem only once.")
expect(err).to include("While it's not a problem now, it could cause errors if you change the version of one of them later.")
end
it "does not throw a warning if a gem is added once in Gemfile and also inside a gemspec as a development dependency" do
- build_lib "my-gem", path: bundled_app do |s|
+ build_lib "my-gem", :path => bundled_app do |s|
s.add_development_dependency "my-private-gem"
end
@@ -413,7 +417,7 @@ RSpec.describe "bundle install with gem sources" do
end
gemfile <<~G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gemspec
@@ -426,180 +430,33 @@ RSpec.describe "bundle install with gem sources" do
expect(the_bundle).to include_gems("my-private-gem 1.0")
end
- it "throws a warning if a gem is added once in Gemfile and also inside a gemspec as a development dependency, with different requirements" do
- build_lib "my-gem", path: bundled_app do |s|
- s.add_development_dependency "rubocop", "~> 1.36.0"
- end
-
- build_repo4 do
- build_gem "rubocop", "1.36.0"
- build_gem "rubocop", "1.37.1"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gemspec
-
- gem "rubocop", group: :development
- G
-
- bundle :install
-
- expect(err).to include("A gemspec development dependency (rubocop, ~> 1.36.0) is being overridden by a Gemfile dependency (rubocop, >= 0).")
- expect(err).to include("This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement")
-
- # This is not the best behavior I believe, it would be better if both
- # requirements are considered if they are compatible, and a version
- # satisfying both is chosen. But not sure about changing it right now, so
- # I went with a warning for the time being.
- expect(the_bundle).to include_gems("rubocop 1.37.1")
- end
-
- it "includes the gem without warning if two gemspecs add it with the same requirement" do
- gem1 = tmp("my-gem-1")
- gem2 = tmp("my-gem-2")
-
- build_lib "my-gem", path: gem1 do |s|
- s.add_development_dependency "rubocop", "~> 1.36.0"
- end
-
- build_lib "my-gem-2", path: gem2 do |s|
- s.add_development_dependency "rubocop", "~> 1.36.0"
- end
-
- build_repo4 do
- build_gem "rubocop", "1.36.0"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gemspec path: "#{gem1}"
- gemspec path: "#{gem2}"
- G
-
- bundle :install
-
- expect(err).to be_empty
- expect(the_bundle).to include_gems("rubocop 1.36.0")
- end
-
- it "warns when a Gemfile dependency is overriding a gemspec development dependency, with different requirements" do
- build_lib "my-gem", path: bundled_app do |s|
- s.add_development_dependency "rails", ">= 5"
- end
-
- build_repo4 do
- build_gem "rails", "7.0.8"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "rails", "~> 7.0.8"
-
- gemspec
- G
-
- bundle :install
-
- expect(err).to include("A gemspec development dependency (rails, >= 5) is being overridden by a Gemfile dependency (rails, ~> 7.0.8).")
- expect(err).to include("This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement")
-
- # This is not the best behavior I believe, it would be better if both
- # requirements are considered if they are compatible, and a version
- # satisfying both is chosen. But not sure about changing it right now, so
- # I went with a warning for the time being.
- expect(the_bundle).to include_gems("rails 7.0.8")
- end
-
- it "does not warn if a gem is added once in Gemfile and also inside a gemspec as a development dependency, with same requirements, and different sources" do
- build_lib "my-gem", path: bundled_app do |s|
- s.add_development_dependency "activesupport"
- end
-
- build_repo4 do
- build_gem "activesupport"
- end
-
- build_git "activesupport", "1.0", path: lib_path("activesupport")
-
- install_gemfile <<~G
- source "https://gem.repo4"
-
- gemspec
-
- gem "activesupport", :git => "#{lib_path("activesupport")}"
- G
-
- expect(err).to be_empty
- expect(the_bundle).to include_gems "activesupport 1.0", source: "git@#{lib_path("activesupport")}"
-
- # if the Gemfile dependency is specified first
- install_gemfile <<~G
- source "https://gem.repo4"
-
- gem "activesupport", :git => "#{lib_path("activesupport")}"
-
- gemspec
- G
-
- expect(err).to be_empty
- expect(the_bundle).to include_gems "activesupport 1.0", source: "git@#{lib_path("activesupport")}"
- end
-
- it "considers both dependencies for resolution if a gem is added once in Gemfile and also inside a local gemspec as a runtime dependency, with different requirements" do
- build_lib "my-gem", path: bundled_app do |s|
- s.add_dependency "rubocop", "~> 1.36.0"
- end
-
- build_repo4 do
- build_gem "rubocop", "1.36.0"
- build_gem "rubocop", "1.37.1"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gemspec
-
- gem "rubocop"
- G
-
- bundle :install
-
- expect(err).to be_empty
- expect(the_bundle).to include_gems("rubocop 1.36.0")
- end
-
it "throws an error if a gem is added twice in Gemfile when version of one dependency is not specified" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
- gem "myrack"
- gem "myrack", "1.0"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
+ gem "rack", "1.0"
G
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).to include("You specified: myrack (>= 0) and myrack (= 1.0).")
+ expect(err).to include("You specified: rack (>= 0) and rack (= 1.0).")
end
it "throws an error if a gem is added twice in Gemfile when different versions of both dependencies are specified" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
- gem "myrack", "1.0"
- gem "myrack", "1.1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "1.0"
+ gem "rack", "1.1"
G
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).to include("You specified: myrack (= 1.0) and myrack (= 1.1).")
+ expect(err).to include("You specified: rack (= 1.0) and rack (= 1.1).")
end
it "gracefully handles error when rubygems server is unavailable" do
skip "networking issue" if Gem.win_platform?
- install_gemfile <<-G, artifice: nil, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :artifice => nil, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
source "http://0.0.0.0:9384" do
gem 'foo'
end
@@ -610,8 +467,8 @@ RSpec.describe "bundle install with gem sources" do
end
it "fails gracefully when downloading an invalid specification from the full index" do
- build_repo2(build_compact_index: false) do
- build_gem "ajp-rails", "0.0.0", gemspec: false, skip_validation: true do |s|
+ build_repo2 do
+ build_gem "ajp-rails", "0.0.0", :gemspec => false, :skip_validation => true do |s|
bad_deps = [["ruby-ajp", ">= 0.2.0"], ["rails", ">= 0.14"]]
s.
instance_variable_get(:@spec).
@@ -622,8 +479,8 @@ RSpec.describe "bundle install with gem sources" do
build_gem "ruby-ajp", "1.0.0"
end
- install_gemfile <<-G, full_index: true, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :full_index => true, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "ajp-rails", "0.0.0"
G
@@ -638,7 +495,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.touch(bundled_app(".bundle/config"))
install_gemfile(<<-G)
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo'
G
@@ -649,7 +506,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.touch("#{Bundler.rubygems.user_home}/.bundle/config")
install_gemfile(<<-G)
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo'
G
@@ -657,11 +514,13 @@ 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
+ install_gemfile <<-G, :raise_on_error => false
ruby '~> 1.2'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
expect(err).to include("Your Ruby version is #{Gem.ruby_version}, but your Gemfile specified ~> 1.2")
end
@@ -671,22 +530,21 @@ RSpec.describe "bundle install with gem sources" do
before do
install_gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
it "writes current Ruby version to Gemfile.lock" do
- checksums = checksums_section_when_enabled
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- #{checksums}
+
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -698,21 +556,19 @@ RSpec.describe "bundle install with gem sources" do
it "updates Gemfile.lock with updated yet still compatible ruby version" do
install_gemfile <<-G
ruby '~> #{current_ruby_minor}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- checksums = checksums_section_when_enabled
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- #{checksums}
+
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -723,7 +579,7 @@ RSpec.describe "bundle install with gem sources" do
it "does not crash when unlocking" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby '>= 2.1.0'
G
@@ -742,14 +598,14 @@ RSpec.describe "bundle install with gem sources" do
build_lib "foo"
gemfile = <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "#{lib_path("foo-1.0")}"
G
File.open("#{root_dir}/Gemfile", "w") do |file|
file.puts gemfile
end
- bundle :install, dir: root_dir
+ bundle :install, :dir => root_dir
end
it "doesn't blow up when using the `gemspec` DSL" do
@@ -757,16 +613,16 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.mkdir_p(root_dir)
- build_lib "foo", path: root_dir
+ build_lib "foo", :path => root_dir
gemfile = <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
File.open("#{root_dir}/Gemfile", "w") do |file|
file.puts gemfile
end
- bundle :install, dir: root_dir
+ bundle :install, :dir => root_dir
end
end
@@ -775,11 +631,11 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set force_ruby_platform true"
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- bundle :install, quiet: true
+ bundle :install, :quiet => true
expect(out).to be_empty
expect(err).to be_empty
end
@@ -805,25 +661,25 @@ RSpec.describe "bundle install with gem sources" do
RUBY
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'non-existing-gem'
G
- bundle :install, quiet: true, raise_on_error: false, env: { "RUBYOPT" => "-r#{bundled_app("install_with_warning.rb")}" }
+ bundle :install, :quiet => true, :raise_on_error => false, :env => { "RUBYOPT" => "-r#{bundled_app("install_with_warning.rb")}" }
expect(out).to be_empty
expect(err).to include("Could not find gem 'non-existing-gem'")
expect(err).to include("BOOOOO")
end
end
- describe "when bundle path does not have cd permission", :permissions do
+ describe "when bundle path does not have write access", :permissions do
let(:bundle_path) { bundled_app("vendor") }
before do
FileUtils.mkdir_p(bundle_path)
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
@@ -831,20 +687,20 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod(0o500, bundle_path)
bundle "config set --local path vendor"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include(bundle_path.to_s)
expect(err).to include("grant write permissions")
end
end
- describe "when bundle gems path does not have cd permission", :permissions do
+ describe "when bundle gems path does not have write access", :permissions do
let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
before do
FileUtils.mkdir_p(gems_path)
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
@@ -853,7 +709,7 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local path vendor"
begin
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
ensure
FileUtils.chmod("+x", gems_path)
end
@@ -861,79 +717,19 @@ RSpec.describe "bundle install with gem sources" do
expect(err).not_to include("ERROR REPORT TEMPLATE")
expect(err).to include(
- "There was an error while trying to create `#{gems_path.join("myrack-1.0.0")}`. " \
+ "There was an error while trying to create `#{gems_path.join("rack-1.0.0")}`. " \
"It is likely that you need to grant executable permissions for all parent directories and write permissions for `#{gems_path}`."
)
end
end
- describe "when bundle bin dir does not have cd permission", :permissions do
- let(:bin_dir) { bundled_app("vendor/#{Bundler.ruby_scope}/bin") }
-
- before do
- FileUtils.mkdir_p(bin_dir)
- gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
- G
- end
-
- it "should display a proper message to explain the problem" do
- FileUtils.chmod("-x", bin_dir)
- bundle "config set --local path vendor"
-
- begin
- bundle :install, raise_on_error: false
- ensure
- FileUtils.chmod("+x", bin_dir)
- end
-
- expect(err).not_to include("ERROR REPORT TEMPLATE")
-
- expect(err).to include(
- "There was an error while trying to write to `#{bin_dir}`. " \
- "It is likely that you need to grant write permissions for that path."
- )
- end
- end
-
- describe "when bundle bin dir does not have write access", :permissions do
- let(:bin_dir) { bundled_app("vendor/#{Bundler.ruby_scope}/bin") }
-
- before do
- FileUtils.mkdir_p(bin_dir)
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
- end
-
- it "should display a proper message to explain the problem" do
- FileUtils.chmod("-w", bin_dir)
- bundle "config set --local path vendor"
-
- begin
- bundle :install, raise_on_error: false
- ensure
- FileUtils.chmod("+w", bin_dir)
- end
-
- expect(err).not_to include("ERROR REPORT TEMPLATE")
-
- expect(err).to include(
- "There was an error while trying to write to `#{bin_dir}`. " \
- "It is likely that you need to grant write permissions for that path."
- )
- end
- end
-
describe "when bundle extensions path does not have write access", :permissions do
let(:extensions_path) { bundled_app("vendor/#{Bundler.ruby_scope}/extensions/#{Gem::Platform.local}/#{Gem.extension_api_version}") }
before do
FileUtils.mkdir_p(extensions_path)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'simple_binary'
G
end
@@ -943,7 +739,7 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local path vendor"
begin
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
ensure
FileUtils.chmod("+x", extensions_path)
end
@@ -957,7 +753,7 @@ RSpec.describe "bundle install with gem sources" do
end
end
- describe "when the path of a specific gem does not have cd permission", :permissions do
+ describe "when the path of a specific gem is not writable", :permissions do
let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
let(:foo_path) { gems_path.join("foo-1.0.0") }
@@ -969,7 +765,7 @@ RSpec.describe "bundle install with gem sources" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo'
G
end
@@ -983,7 +779,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod("-x", foo_path)
begin
- bundle "install --redownload", raise_on_error: false
+ bundle "install --redownload", :raise_on_error => false
ensure
FileUtils.chmod("+x", foo_path)
end
@@ -994,107 +790,14 @@ 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 "https://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 "https://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("Bundler cannot reinstall foo-1.0.0 because there's a previous installation of it at #{gems_path}/foo-1.0.0 that is unsafe to remove")
- end
- end
-
- describe "when gems path is world writable (no sticky bit set), but previous install is just an empty dir (like it happens with default gems)", :permissions do
- let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
- let(:full_path) { gems_path.join("foo-1.0.0") }
-
- before do
- build_repo4 do
- build_gem "foo", "1.0.0" do |s|
- s.write "CHANGELOG.md", "foo"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem 'foo'
- G
- end
-
- it "does not try to remove the directory and thus don't abort with an error about unsafe directory removal" do
- bundle "config set --local path vendor"
-
- FileUtils.mkdir_p(gems_path)
- FileUtils.chmod(0o777, gems_path)
- Dir.mkdir(full_path)
-
- bundle "install"
- end
- end
-
describe "when bundle cache path does not have write access", :permissions do
let(:cache_path) { bundled_app("vendor/#{Bundler.ruby_scope}/cache") }
before do
FileUtils.mkdir_p(cache_path)
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
@@ -1102,48 +805,25 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod(0o500, cache_path)
bundle "config set --local path vendor"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include(cache_path.to_s)
expect(err).to include("grant write permissions")
end
end
- describe "when gemspecs are unreadable", :permissions do
- let(:gemspec_path) { vendored_gems("specifications/myrack-1.0.0.gemspec") }
-
- before do
- gemfile <<~G
- source "https://gem.repo1"
- gem 'myrack'
- G
- bundle "config path vendor/bundle"
- bundle :install
- expect(out).to include("Bundle complete!")
- expect(err).to be_empty
-
- FileUtils.chmod("-r", gemspec_path)
- end
-
- it "shows a good error" do
- bundle :install, raise_on_error: false
- expect(err).to include(gemspec_path.to_s)
- expect(err).to include("grant read permissions")
- end
- end
-
context "after installing with --standalone" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set --local path bundle"
- bundle "install", standalone: true
+ bundle "install", :standalone => true
end
it "includes the standalone path" do
- bundle "binstubs myrack", standalone: true
- standalone_line = File.read(bundled_app("bin/myrackup")).each_line.find {|line| line.include? "$:.unshift" }.strip
+ bundle "binstubs rack", :standalone => true
+ standalone_line = File.read(bundled_app("bin/rackup")).each_line.find {|line| line.include? "$:.unshift" }.strip
expect(standalone_line).to eq %($:.unshift File.expand_path "../bundle", __dir__)
end
end
@@ -1157,34 +837,30 @@ RSpec.describe "bundle install with gem sources" do
end
it "should display a helpful message explaining how to fix it" do
- bundle :install, env: { "BUNDLE_RUBYGEMS__ORG" => "user:pass{word" }, raise_on_error: false
+ bundle :install, :env => { "BUNDLE_RUBYGEMS__ORG" => "user:pass{word" }, :raise_on_error => false
expect(exitstatus).to eq(17)
expect(err).to eq("Please CGI escape your usernames and passwords before " \
"setting them for authentication.")
end
end
- context "when current platform not included in the lockfile" do
- around do |example|
+ context "in a frozen bundle" do
+ before do
build_repo4 do
build_gem "libv8", "8.4.255.0" do |s|
s.platform = "x86_64-darwin-19"
end
-
- build_gem "libv8", "8.4.255.0" do |s|
- s.platform = "x86_64-linux"
- end
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "libv8"
G
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
libv8 (8.4.255.0-x86_64-darwin-19)
@@ -1198,36 +874,11 @@ RSpec.describe "bundle install with gem sources" do
#{Bundler::VERSION}
L
- simulate_platform("x86_64-linux", &example)
- end
-
- it "adds the current platform to the lockfile" do
- bundle "install --verbose"
-
- expect(out).to include("re-resolving dependencies because your lockfile does not include the current platform")
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- libv8 (8.4.255.0-x86_64-darwin-19)
- libv8 (8.4.255.0-x86_64-linux)
-
- PLATFORMS
- x86_64-darwin-19
- x86_64-linux
-
- DEPENDENCIES
- libv8
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
+ bundle "config set --local deployment true"
end
- it "fails loudly if frozen mode set" do
- bundle "config set --local deployment true"
- bundle "install", raise_on_error: false
+ it "should fail loudly if the lockfile platforms don't include the current platform" do
+ simulate_platform(Gem::Platform.new("x86_64-linux")) { bundle "install", :raise_on_error => false }
expect(err).to eq(
"Your bundle only supports platforms [\"x86_64-darwin-19\"] but your local platform is x86_64-linux. " \
@@ -1239,23 +890,23 @@ 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_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_dependency "racca", "~> 1.4"
+ s.add_runtime_dependency "racc", "~> 1.4"
end
build_gem "crass", "1.0.6"
build_gem "loofah", "2.12.0" do |s|
- s.add_dependency "crass", "~> 1.0.2"
- s.add_dependency "nokogiri", ">= 1.5.9"
+ s.add_runtime_dependency "crass", "~> 1.0.2"
+ s.add_runtime_dependency "nokogiri", ">= 1.5.9"
end
end
@@ -1267,13 +918,6 @@ RSpec.describe "bundle install with gem sources" do
gem "loofah", "~> 2.12.0"
G
- checksums = checksums_section do |c|
- c.checksum gem_repo4, "crass", "1.0.6"
- c.checksum gem_repo4, "loofah", "2.12.0"
- c.checksum gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
- c.checksum gem_repo4, "racca", "1.5.2"
- end
-
lockfile <<-L
GEM
remote: https://gem.repo4/
@@ -1283,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
@@ -1292,7 +936,7 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
loofah (~> 2.12.0)
- #{checksums}
+
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1305,15 +949,7 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local path vendor/bundle"
simulate_platform "x86_64-linux" do
- bundle "install", artifice: "compact_index"
- end
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "crass", "1.0.6"
- c.checksum gem_repo4, "loofah", "2.12.0"
- c.checksum gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
- c.checksum gem_repo4, "racca", "1.5.2"
- c.checksum gem_repo4, "nokogiri", "1.12.4", "x86_64-linux"
+ bundle "install", :artifice => "compact_index"
end
expect(lockfile).to eq <<~L
@@ -1325,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
@@ -1336,7 +972,7 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
loofah (~> 2.12.0)
- #{checksums}
+
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1348,15 +984,15 @@ RSpec.describe "bundle install with gem sources" do
context "with --local flag" do
before do
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
end
it "respects installed gems without fetching any remote sources" do
- install_gemfile <<-G, local: true
- source "https://gem.repo1"
+ install_gemfile <<-G, :local => true
+ source "#{file_uri_for(gem_repo1)}"
source "https://not-existing-source" do
- gem "myrack"
+ gem "rack"
end
G
@@ -1371,14 +1007,14 @@ RSpec.describe "bundle install with gem sources" do
it "installs only gems of the specified groups" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
- gem "myrack", group: :a
+ gem "rack", group: :a
gem "rake", group: :b
gem "yard", group: :c
G
- expect(out).to include("Installing myrack")
+ expect(out).to include("Installing rack")
expect(out).to include("Installing rake")
expect(out).not_to include("Installing yard")
end
@@ -1390,22 +1026,14 @@ RSpec.describe "bundle install with gem sources" do
build_gem "foo", "1.0.1"
build_gem "foo", "1.0.0"
build_gem "bar", "1.0.0"
-
- build_gem "a", "1.0.0" do |s|
- s.add_dependency "foo", "~> 1.0.0"
- end
-
- build_gem "b", "1.0.0" do |s|
- s.add_dependency "foo", "~> 1.0.1"
- end
end
- system_gems "foo-1.0.0", path: default_bundle_path, gem_repo: gem_repo4
+ system_gems "foo-1.0.0", :path => default_bundle_path, :gem_repo => gem_repo4
end
- it "fetches remote sources when not available locally" do
- install_gemfile <<-G, "prefer-local": true, verbose: true
- source "https://gem.repo4"
+ it "fetches remote sources only when not available locally" do
+ install_gemfile <<-G, :"prefer-local" => true, :verbose => true
+ source "#{file_uri_for(gem_repo4)}"
gem "foo"
gem "bar"
@@ -1414,40 +1042,6 @@ RSpec.describe "bundle install with gem sources" do
expect(out).to include("Using foo 1.0.0").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0")
expect(last_command).to be_success
end
-
- it "fetches remote sources when local version does not match requirements" do
- install_gemfile <<-G, "prefer-local": true, verbose: true
- source "https://gem.repo4"
-
- gem "foo", "1.0.1"
- gem "bar"
- G
-
- expect(out).to include("Fetching foo 1.0.1").and include("Installing foo 1.0.1").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0")
- expect(last_command).to be_success
- end
-
- it "uses the locally available version for sub-dependencies when possible" do
- install_gemfile <<-G, "prefer-local": true, verbose: true
- source "https://gem.repo4"
-
- gem "a"
- G
-
- expect(out).to include("Using foo 1.0.0").and include("Fetching a 1.0.0").and include("Installing a 1.0.0")
- expect(last_command).to be_success
- end
-
- it "fetches remote sources for sub-dependencies when the locally available version does not satisfy the requirement" do
- install_gemfile <<-G, "prefer-local": true, verbose: true
- source "https://gem.repo4"
-
- gem "b"
- G
-
- expect(out).to include("Fetching foo 1.0.1").and include("Installing foo 1.0.1").and include("Fetching b 1.0.0").and include("Installing b 1.0.0")
- expect(last_command).to be_success
- end
end
context "with a symlinked configured as bundle path and a gem with symlinks" do
@@ -1468,7 +1062,7 @@ RSpec.describe "bundle install with gem sources" do
File.symlink("../../README.markdown", File.join(man_path, "README.markdown"))
build_repo4 do
- build_gem "binman", path: gem_repo4("gems"), lib_path: binman_path, no_default: true do |s|
+ build_gem "binman", :path => gem_repo4("gems"), :lib_path => binman_path, :no_default => true do |s|
s.files = ["README.markdown", "man/man0/README.markdown"]
end
end
@@ -1476,7 +1070,7 @@ RSpec.describe "bundle install with gem sources" do
it "installs fine" do
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "binman"
G
@@ -1498,110 +1092,15 @@ RSpec.describe "bundle install with gem sources" do
it "does not crash unexpectedly" do
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "autobuild", "1.10.rc2"
G
- bundle "install --jobs 1", raise_on_error: false
+ bundle "install --jobs 1", :raise_on_error => false
expect(err).not_to include("ERROR REPORT TEMPLATE")
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 "https://gem.repo4"
-
- gem "aaa"
- gem "zzz"
- G
-
- lockfile <<~L
- GEM
- remote: https://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
-
- context "when --jobs option given" do
- before do
- install_gemfile "source 'https://gem.repo1'", jobs: 1
- end
-
- it "does not save the flag to config" do
- expect(bundled_app(".bundle/config")).not_to exist
- end
- end
-
- context "when bundler installation is corrupt" do
- before do
- system_gems "bundler-9.99.8"
-
- replace_version_file("9.99.9", dir: system_gem_path("gems/bundler-9.99.8"))
- end
-
- it "shows a proper error" do
- lockfile <<~L
- GEM
- remote: https://gem.repo1/
- specs:
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
-
- BUNDLED WITH
- 9.99.8
- L
-
- install_gemfile "source \"https://gem.repo1\"", env: { "BUNDLER_VERSION" => "9.99.8" }, raise_on_error: false
-
- expect(err).not_to include("ERROR REPORT TEMPLATE")
- expect(err).to include("The running version of Bundler (9.99.9) does not match the version of the specification installed for it (9.99.8)")
- end
- end
-
- it "only installs executable files in bin" do
- bundle "config set --local path vendor/bundle"
-
- install_gemfile <<~G
- source "https://gem.repo1"
- gem "myrack"
- G
-
- expected_executables = [vendored_gems("bin/myrackup").to_s]
- expected_executables << vendored_gems("bin/myrackup.bat").to_s if Gem.win_platform?
- expect(Dir.glob(vendored_gems("bin/*"))).to eq(expected_executables)
- end
end
diff --git a/spec/bundler/commands/issue_spec.rb b/spec/bundler/commands/issue_spec.rb
index 346cdedc42..143f6333ce 100644
--- a/spec/bundler/commands/issue_spec.rb
+++ b/spec/bundler/commands/issue_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle issue" do
it "exits with a message" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
diff --git a/spec/bundler/commands/licenses_spec.rb b/spec/bundler/commands/licenses_spec.rb
index bfec938efd..a203984890 100644
--- a/spec/bundler/commands/licenses_spec.rb
+++ b/spec/bundler/commands/licenses_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe "bundle licenses" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
gem "with_license"
G
@@ -24,7 +24,7 @@ RSpec.describe "bundle licenses" do
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
gem "with_license"
gem "foo"
diff --git a/spec/bundler/commands/list_spec.rb b/spec/bundler/commands/list_spec.rb
index cc0db9169d..66930ded75 100644
--- a/spec/bundler/commands/list_spec.rb
+++ b/spec/bundler/commands/list_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle list" do
context "with name-only and paths option" do
it "raises an error" do
- bundle "list --name-only --paths", raise_on_error: false
+ bundle "list --name-only --paths", :raise_on_error => false
expect(err).to eq "The `--name-only` and `--paths` options cannot be used together"
end
@@ -11,7 +11,7 @@ RSpec.describe "bundle list" do
context "with without-group and only-group option" do
it "raises an error" do
- bundle "list --without-group dev --only-group test", raise_on_error: false
+ bundle "list --without-group dev --only-group test", :raise_on_error => false
expect(err).to eq "The `--only-group` and `--without-group` options cannot be used together"
end
@@ -20,9 +20,9 @@ RSpec.describe "bundle list" do
describe "with without-group option" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
gem "rails", :group => [:production]
G
@@ -32,7 +32,7 @@ RSpec.describe "bundle list" do
it "prints the gems not in the specified group" do
bundle "list --without-group test"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
expect(out).to include(" * rails (2.3.2)")
expect(out).not_to include(" * rspec (1.2.7)")
end
@@ -40,7 +40,7 @@ RSpec.describe "bundle list" do
context "when group is not found" do
it "raises an error" do
- bundle "list --without-group random", raise_on_error: false
+ bundle "list --without-group random", :raise_on_error => false
expect(err).to eq "`random` group could not be found."
end
@@ -50,7 +50,7 @@ RSpec.describe "bundle list" do
it "prints the gems not in the specified groups" do
bundle "list --without-group test production"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
expect(out).not_to include(" * rails (2.3.2)")
expect(out).not_to include(" * rspec (1.2.7)")
end
@@ -60,9 +60,9 @@ RSpec.describe "bundle list" do
describe "with only-group option" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
gem "rails", :group => [:production]
G
@@ -72,14 +72,14 @@ RSpec.describe "bundle list" do
it "prints the gems in the specified group" do
bundle "list --only-group default"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
expect(out).not_to include(" * rspec (1.2.7)")
end
end
context "when group is not found" do
it "raises an error" do
- bundle "list --only-group random", raise_on_error: false
+ bundle "list --only-group random", :raise_on_error => false
expect(err).to eq "`random` group could not be found."
end
@@ -89,7 +89,7 @@ RSpec.describe "bundle list" do
it "prints the gems in the specified groups" do
bundle "list --only-group default production"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
expect(out).to include(" * rails (2.3.2)")
expect(out).not_to include(" * rspec (1.2.7)")
end
@@ -99,9 +99,9 @@ RSpec.describe "bundle list" do
context "with name-only option" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
G
end
@@ -109,7 +109,7 @@ RSpec.describe "bundle list" do
it "prints only the name of the gems in the bundle" do
bundle "list --name-only"
- expect(out).to include("myrack")
+ expect(out).to include("rack")
expect(out).to include("rspec")
end
end
@@ -117,32 +117,32 @@ RSpec.describe "bundle list" do
context "with paths option" do
before do
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "bar"
end
- build_git "git_test", "1.0.0", path: lib_path("git_test")
+ build_git "git_test", "1.0.0", :path => lib_path("git_test")
- build_lib("gemspec_test", path: tmp("gemspec_test")) do |s|
+ build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
s.add_dependency "bar", "=1.0.0"
end
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "rails"
gem "git_test", :git => "#{lib_path("git_test")}"
- gemspec :path => "#{tmp("gemspec_test")}"
+ gemspec :path => "#{tmp.join("gemspec_test")}"
G
end
it "prints the path of each gem in the bundle" do
bundle "list --paths"
expect(out).to match(%r{.*\/rails\-2\.3\.2})
- expect(out).to match(%r{.*\/myrack\-1\.2})
+ expect(out).to match(%r{.*\/rack\-1\.2})
expect(out).to match(%r{.*\/git_test\-\w})
expect(out).to match(%r{.*\/gemspec_test})
end
@@ -151,7 +151,7 @@ RSpec.describe "bundle list" do
context "when no gems are in the gemfile" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
@@ -164,25 +164,25 @@ RSpec.describe "bundle list" do
context "without options" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
G
end
it "lists gems installed in the bundle" do
bundle "list"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
end
end
context "when using the ls alias" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
G
end
diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb
index 5e2a6e7e8f..08ac333664 100644
--- a/spec/bundler/commands/lock_spec.rb
+++ b/spec/bundler/commands/lock_spec.rb
@@ -1,22 +1,27 @@
# frozen_string_literal: true
RSpec.describe "bundle lock" do
- let(:expected_lockfile) do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.2"
- c.checksum gem_repo4, "actionpack", "2.3.2"
- c.checksum gem_repo4, "activerecord", "2.3.2"
- c.checksum gem_repo4, "activeresource", "2.3.2"
- c.checksum gem_repo4, "activesupport", "2.3.2"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.2"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
+ 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 }
- <<~L
+ before :each do
+ gemfile <<-G
+ source "#{file_uri_for(repo)}"
+ gem "rails"
+ gem "weakling"
+ gem "foo"
+ G
+
+ @lockfile = strip_lockfile(<<-L)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(repo)}/
specs:
actionmailer (2.3.2)
activesupport (= 2.3.2)
@@ -33,8 +38,8 @@ RSpec.describe "bundle lock" do
actionpack (= 2.3.2)
activerecord (= 2.3.2)
activeresource (= 2.3.2)
- rake (= #{rake_version})
- rake (#{rake_version})
+ rake (= 13.0.1)
+ rake (13.0.1)
weakling (0.0.3)
PLATFORMS
@@ -44,219 +49,54 @@ RSpec.describe "bundle lock" do
foo
rails
weakling
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- let(:outdated_lockfile) do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.1"
- c.checksum gem_repo4, "actionpack", "2.3.1"
- c.checksum gem_repo4, "activerecord", "2.3.1"
- c.checksum gem_repo4, "activeresource", "2.3.1"
- c.checksum gem_repo4, "activesupport", "2.3.1"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.1"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
-
- <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- actionmailer (2.3.1)
- activesupport (= 2.3.1)
- actionpack (2.3.1)
- activesupport (= 2.3.1)
- activerecord (2.3.1)
- activesupport (= 2.3.1)
- activeresource (2.3.1)
- activesupport (= 2.3.1)
- activesupport (2.3.1)
- foo (1.0)
- rails (2.3.1)
- actionmailer (= 2.3.1)
- actionpack (= 2.3.1)
- activerecord (= 2.3.1)
- activeresource (= 2.3.1)
- rake (= #{rake_version})
- rake (#{rake_version})
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
- DEPENDENCIES
- foo
- rails
- weakling
- #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
- before :each do
- build_repo4 do
- FileUtils.cp rake_path, "#{gem_repo4}/gems/"
-
- build_gem "rake", "10.0.1"
-
- %w[2.3.1 2.3.2].each do |version|
- build_gem "rails", version do |s|
- s.executables = "rails"
- s.add_dependency "rake", version == "2.3.1" ? "10.0.1" : rake_version
- s.add_dependency "actionpack", version
- s.add_dependency "activerecord", version
- s.add_dependency "actionmailer", version
- s.add_dependency "activeresource", version
- end
- build_gem "actionpack", version do |s|
- s.add_dependency "activesupport", version
- end
- build_gem "activerecord", version do |s|
- s.add_dependency "activesupport", version
- end
- build_gem "actionmailer", version do |s|
- s.add_dependency "activesupport", version
- end
- build_gem "activeresource", version do |s|
- s.add_dependency "activesupport", version
- end
- build_gem "activesupport", version
- end
-
- build_gem "weakling", "0.0.3"
-
- build_gem "foo"
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem "rails"
- gem "weakling"
- gem "foo"
- G
- end
-
it "prints a lockfile when there is no existing lockfile with --print" do
bundle "lock --print"
- expect(out).to eq(expected_lockfile.chomp)
+ expect(out).to eq(@lockfile)
end
it "prints a lockfile when there is an existing lockfile with --print" do
- lockfile expected_lockfile
+ lockfile @lockfile
bundle "lock --print"
- expect(out).to eq(expected_lockfile.chomp)
- end
-
- it "prints a lockfile when there is an existing checksums lockfile with --print" do
- lockfile expected_lockfile
-
- bundle "lock --print"
-
- expect(out).to eq(expected_lockfile.chomp)
+ expect(out).to eq(@lockfile)
end
it "writes a lockfile when there is no existing lockfile" do
bundle "lock"
- expect(read_lockfile).to eq(expected_lockfile)
- end
-
- it "prints a lockfile without fetching new checksums if the existing lockfile had no checksums" do
- lockfile expected_lockfile
-
- bundle "lock --print"
-
- expect(out).to eq(expected_lockfile.chomp)
- end
-
- it "touches the lockfile when there is an existing lockfile that does not need changes" do
- lockfile expected_lockfile
-
- expect do
- bundle "lock"
- end.to change { bundled_app_lock.mtime }
- end
-
- it "does not touch lockfile with --print" do
- lockfile expected_lockfile
-
- expect do
- bundle "lock --print"
- end.not_to change { bundled_app_lock.mtime }
+ expect(read_lockfile).to eq(@lockfile)
end
it "writes a lockfile when there is an outdated lockfile using --update" do
- lockfile outdated_lockfile
+ lockfile @lockfile.gsub("2.3.2", "2.3.1")
bundle "lock --update"
- expect(read_lockfile).to eq(expected_lockfile)
- end
-
- it "prints an updated lockfile when there is an outdated lockfile using --print --update" do
- lockfile outdated_lockfile
-
- bundle "lock --print --update"
-
- expect(out).to eq(expected_lockfile.rstrip)
- end
-
- it "emits info messages to stderr when updating an outdated lockfile using --print --update" do
- lockfile outdated_lockfile
-
- bundle "lock --print --update"
-
- expect(err).to eq(<<~STDERR.rstrip)
- Fetching gem metadata from https://gem.repo4/...
- Resolving dependencies...
- STDERR
- end
-
- it "writes a lockfile when there is an outdated lockfile and bundle is frozen" do
- lockfile outdated_lockfile
-
- bundle "lock --update", env: { "BUNDLE_FROZEN" => "true" }
-
- expect(read_lockfile).to eq(expected_lockfile)
+ expect(read_lockfile).to eq(@lockfile)
end
it "does not fetch remote specs when using the --local option" do
- bundle "lock --update --local", raise_on_error: false
+ bundle "lock --update --local", :raise_on_error => false
expect(err).to match(/locally installed gems/)
end
- it "does not fetch remote checksums with --local" do
- lockfile expected_lockfile
-
- bundle "lock --print --local"
-
- expect(out).to eq(expected_lockfile.chomp)
- end
-
it "works with --gemfile flag" do
- gemfile "CustomGemfile", <<-G
- source "https://gem.repo4"
+ create_file "CustomGemfile", <<-G
+ source "#{file_uri_for(repo)}"
gem "foo"
G
- bundle "lock --gemfile CustomGemfile"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "foo", "1.0"
- end
-
- lockfile = <<~L
+ lockfile = strip_lockfile(<<-L)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(repo)}/
specs:
foo (1.0)
@@ -265,10 +105,12 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
foo
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
+ bundle "lock --gemfile CustomGemfile"
+
expect(out).to match(/Writing lockfile to.+CustomGemfile\.lock/)
expect(read_lockfile("CustomGemfile.lock")).to eq(lockfile)
expect { read_lockfile }.to raise_error(Errno::ENOENT)
@@ -278,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(expected_lockfile)
+ expect(read_lockfile("lock")).to eq(@lockfile)
expect { read_lockfile }.to raise_error(Errno::ENOENT)
end
@@ -286,319 +128,37 @@ RSpec.describe "bundle lock" do
bundle "install"
bundle "lock --lockfile=lock"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.2"
- c.checksum gem_repo4, "actionpack", "2.3.2"
- c.checksum gem_repo4, "activerecord", "2.3.2"
- c.checksum gem_repo4, "activeresource", "2.3.2"
- c.checksum gem_repo4, "activesupport", "2.3.2"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.2"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
-
- lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- 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 (= #{rake_version})
- rake (#{rake_version})
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- rails
- weakling
- #{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
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.1"
- c.checksum gem_repo4, "actionpack", "2.3.1"
- c.checksum gem_repo4, "activerecord", "2.3.1"
- c.checksum gem_repo4, "activeresource", "2.3.1"
- c.checksum gem_repo4, "activesupport", "2.3.1"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.1"
- c.checksum gem_repo4, "rake", "10.0.1"
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
-
- lockfile_with_outdated_rails_and_rake = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- actionmailer (2.3.1)
- activesupport (= 2.3.1)
- actionpack (2.3.1)
- activesupport (= 2.3.1)
- activerecord (2.3.1)
- activesupport (= 2.3.1)
- activeresource (2.3.1)
- activesupport (= 2.3.1)
- activesupport (2.3.1)
- foo (1.0)
- rails (2.3.1)
- actionmailer (= 2.3.1)
- actionpack (= 2.3.1)
- activerecord (= 2.3.1)
- activeresource (= 2.3.1)
- rake (= 10.0.1)
- rake (10.0.1)
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- rails
- weakling
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- lockfile lockfile_with_outdated_rails_and_rake
+ lockfile @lockfile.gsub("2.3.2", "2.3.1").gsub("13.0.1", "10.0.1")
bundle "lock --update rails rake"
- expect(read_lockfile).to eq(expected_lockfile)
- end
-
- it "updates specific gems using --update, even if that requires unlocking other top level gems" do
- build_repo4 do
- build_gem "prism", "0.15.1"
- build_gem "prism", "0.24.0"
-
- build_gem "ruby-lsp", "0.12.0" do |s|
- s.add_dependency "prism", "< 0.24.0"
- end
-
- build_gem "ruby-lsp", "0.16.1" do |s|
- s.add_dependency "prism", ">= 0.24.0"
- end
-
- build_gem "tapioca", "0.11.10" do |s|
- s.add_dependency "prism", "< 0.24.0"
- end
-
- build_gem "tapioca", "0.13.1" do |s|
- s.add_dependency "prism", ">= 0.24.0"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "tapioca"
- gem "ruby-lsp"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4
- specs:
- prism (0.15.1)
- ruby-lsp (0.12.0)
- prism (< 0.24.0)
- tapioca (0.11.10)
- prism (< 0.24.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- ruby-lsp
- tapioca
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock --update tapioca --verbose"
-
- expect(lockfile).to include("tapioca (0.13.1)")
- end
-
- it "updates specific gems using --update, even if that requires unlocking other top level gems, but only as few as possible" do
- build_repo4 do
- build_gem "prism", "0.15.1"
- build_gem "prism", "0.24.0"
-
- build_gem "ruby-lsp", "0.12.0" do |s|
- s.add_dependency "prism", "< 0.24.0"
- end
-
- build_gem "ruby-lsp", "0.16.1" do |s|
- s.add_dependency "prism", ">= 0.24.0"
- end
-
- build_gem "tapioca", "0.11.10" do |s|
- s.add_dependency "prism", "< 0.24.0"
- end
-
- build_gem "tapioca", "0.13.1" do |s|
- s.add_dependency "prism", ">= 0.24.0"
- end
-
- build_gem "other-prism-dependent", "1.0.0" do |s|
- s.add_dependency "prism", ">= 0.15.1"
- end
-
- build_gem "other-prism-dependent", "1.1.0" do |s|
- s.add_dependency "prism", ">= 0.15.1"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "tapioca"
- gem "ruby-lsp"
- gem "other-prism-dependent"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4
- specs:
- other-prism-dependent (1.0.0)
- prism (>= 0.15.1)
- prism (0.15.1)
- ruby-lsp (0.12.0)
- prism (< 0.24.0)
- tapioca (0.11.10)
- prism (< 0.24.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- ruby-lsp
- tapioca
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock --update tapioca"
-
- expect(lockfile).to include("tapioca (0.13.1)")
- expect(lockfile).to include("other-prism-dependent (1.0.0)")
- end
-
- it "preserves unknown checksum algorithms" do
- lockfile expected_lockfile.gsub(/(sha256=[a-f0-9]+)$/, "constant=true,\\1,xyz=123")
-
- previous_lockfile = read_lockfile
-
- bundle "lock"
-
- expect(read_lockfile).to eq(previous_lockfile)
- end
-
- it "does not unlock git sources when only uri shape changes" do
- build_git("foo")
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}"
- G
-
- # Change uri format to end with "/" and reinstall
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}/"
- G
-
- expect(out).to include("using resolution from the lockfile")
- expect(out).not_to include("re-resolving dependencies because the list of sources changed")
- end
-
- it "updates specific gems using --update using the locked revision of unrelated git gems for resolving" do
- ref = build_git("foo").ref_for("HEAD")
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "rake"
- gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "deadbeef"
- G
-
- lockfile <<~L
- GIT
- remote: #{lib_path("foo-1.0")}
- revision: #{ref}
- branch: deadbeef
- specs:
- foo (1.0)
-
- GEM
- remote: https://gem.repo1/
- specs:
- rake (10.0.1)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo!
- rake
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock --update rake --verbose"
- expect(out).to match(/Writing lockfile to.+lock/)
- expect(lockfile).to include("rake (#{rake_version})")
+ expect(read_lockfile).to eq(@lockfile)
end
it "errors when updating a missing specific gems using --update" do
- lockfile expected_lockfile
+ lockfile @lockfile
- bundle "lock --update blahblah", raise_on_error: false
+ bundle "lock --update blahblah", :raise_on_error => false
expect(err).to eq("Could not find gem 'blahblah'.")
- expect(read_lockfile).to eq(expected_lockfile)
+ expect(read_lockfile).to eq(@lockfile)
end
it "can lock without downloading gems" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
- gem "myrack_middleware", :group => "test"
+ gem "rack_middleware", :group => "test"
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
@@ -625,7 +185,7 @@ RSpec.describe "bundle lock" do
# establish a lockfile set to 1.4.3
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo', '1.4.3'
gem 'bar', '2.0.3'
gem 'qux', '1.0.0'
@@ -634,7 +194,7 @@ RSpec.describe "bundle lock" do
# remove 1.4.3 requirement and bar altogether
# to setup update specs below
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo'
gem 'qux'
G
@@ -654,22 +214,6 @@ RSpec.describe "bundle lock" do
expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[foo-1.5.0 bar-2.1.1 qux-1.1.0].sort)
end
- it "shows proper error when Gemfile changes forbid patch upgrades, and --patch --strict is given" do
- # force next minor via Gemfile
- gemfile <<-G
- source "https://gem.repo4"
- gem 'foo', '1.5.0'
- gem 'qux'
- G
-
- bundle "lock --update foo --patch --strict", raise_on_error: false
-
- expect(err).to include(
- "foo is locked to 1.4.3, while Gemfile is requesting foo (= 1.5.0). " \
- "--strict --patch was specified, but there are no patch level upgrades from 1.4.3 satisfying foo (= 1.5.0), so version solving has failed"
- )
- end
-
context "pre" do
it "defaults to major" do
bundle "lock --update --pre"
@@ -697,68 +241,24 @@ 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 "https://gem.repo4"
- gem 'sequel'
- G
-
- lockfile <<~L
- GEM
- remote: https://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
+ it "updates the bundler version in the lockfile without re-resolving", :rubygems => ">= 3.3.0.dev" do
build_repo4 do
- build_gem "bundler", "55"
+ build_gem "rack", "1.0"
end
- system_gems "bundler-55", gem_repo: gem_repo4
-
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "https://gem.repo4"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2')
- bundle "lock --update --bundler --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- expect(lockfile).to end_with("BUNDLED WITH\n 55\n")
+ FileUtils.rm_r gem_repo4
- update_repo4 do
- build_gem "bundler", "99"
- end
+ bundle "lock --update --bundler"
+ expect(the_bundle).to include_gem "rack 1.0"
- bundle "lock --update --bundler --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- expect(lockfile).to end_with("BUNDLED WITH\n 99\n")
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
+ expect(the_bundle.locked_gems.bundler_version).to eq v(Bundler::VERSION)
end
it "supports adding new platforms" do
@@ -766,76 +266,20 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(default_platform_list(java, x86_mingw32))
- end
-
- it "supports adding new platforms, when most specific locked platform is not the current platform, and current resolve is not compatible with the target platform" do
- simulate_platform "arm64-darwin-23" do
- build_repo4 do
- build_gem "foo" do |s|
- s.platform = "arm64-darwin"
- end
-
- build_gem "foo" do |s|
- s.platform = "java"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
-
- gem "foo"
- G
-
- lockfile <<-L
- GEM
- remote: https://gem.repo4/
- specs:
- foo (1.0-arm64-darwin)
-
- PLATFORMS
- arm64-darwin
-
- DEPENDENCIES
- foo
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock --add-platform java"
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- foo (1.0-arm64-darwin)
- foo (1.0-java)
-
- PLATFORMS
- arm64-darwin
- java
-
- DEPENDENCIES
- foo
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
+ expect(lockfile.platforms).to match_array([java, x86_mingw32, specific_local_platform].uniq)
end
it "supports adding new platforms with force_ruby_platform = true" do
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0)
- platform_specific (1.0-x86-64_linux)
+ platform_specific (1.0-x86-linux)
PLATFORMS
ruby
- x86_64-linux
+ x86-linux
DEPENDENCIES
platform_specific
@@ -854,13 +298,12 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(default_platform_list("ruby"))
+ expect(lockfile.platforms).to match_array(["ruby", specific_local_platform].uniq)
end
- it "fails when adding an unknown platform" do
- bundle "lock --add-platform foobarbaz", raise_on_error: false
- expect(err).to include("The platform `foobarbaz` is unknown to RubyGems and can't be added to the lockfile")
- expect(last_command).to be_failure
+ it "warns when adding an unknown platform" do
+ bundle "lock --add-platform foobarbaz"
+ expect(err).to include("The platform `foobarbaz` is unknown to RubyGems and adding it will likely lead to resolution errors")
end
it "allows removing platforms" do
@@ -868,12 +311,12 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(default_platform_list(java, x86_mingw32))
+ expect(lockfile.platforms).to match_array([java, x86_mingw32, specific_local_platform].uniq)
bundle "lock --remove-platform java"
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(default_platform_list(x86_mingw32))
+ expect(lockfile.platforms).to match_array([x86_mingw32, specific_local_platform].uniq)
end
it "also cleans up redundant platform gems when removing platforms" do
@@ -884,14 +327,9 @@ RSpec.describe "bundle lock" do
end
end
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.12.0"
- c.checksum gem_repo4, "nokogiri", "1.12.0", "x86_64-darwin"
- end
-
simulate_platform "x86_64-darwin-22" do
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
G
@@ -899,7 +337,7 @@ RSpec.describe "bundle lock" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.12.0)
nokogiri (1.12.0-x86_64-darwin)
@@ -910,20 +348,18 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
nokogiri
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
- checksums.delete("nokogiri", Gem::Platform::RUBY)
-
simulate_platform "x86_64-darwin-22" do
bundle "lock --remove-platform ruby"
end
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.12.0-x86_64-darwin)
@@ -932,14 +368,14 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
nokogiri
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "errors when removing all platforms" do
- bundle "lock --remove-platform #{local_platform}", raise_on_error: false
+ bundle "lock --remove-platform #{specific_local_platform}", :raise_on_error => false
expect(err).to include("Removing all platforms from the bundle is not allowed")
end
@@ -974,7 +410,7 @@ RSpec.describe "bundle lock" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "mixlib-shellout"
gem "gssapi"
@@ -982,16 +418,9 @@ RSpec.describe "bundle lock" do
simulate_platform(x86_mingw32) { bundle :lock }
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "ffi", "1.9.14", "x86-mingw32"
- c.checksum gem_repo4, "gssapi", "1.2.0"
- c.checksum gem_repo4, "mixlib-shellout", "2.2.6", "universal-mingw32"
- c.checksum gem_repo4, "win32-process", "0.8.3"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
ffi (1.9.14-x86-mingw32)
gssapi (1.2.0)
@@ -1007,7 +436,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
gssapi
mixlib-shellout
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1015,12 +444,9 @@ RSpec.describe "bundle lock" do
bundle "config set --local force_ruby_platform true"
bundle :lock
- checksums.checksum gem_repo4, "ffi", "1.9.14"
- checksums.checksum gem_repo4, "mixlib-shellout", "2.2.6"
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
ffi (1.9.14)
ffi (1.9.14-x86-mingw32)
@@ -1039,7 +465,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
gssapi
mixlib-shellout
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1058,14 +484,14 @@ RSpec.describe "bundle lock" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "libv8"
G
lockfile <<-G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
libv8 (8.4.255.0)
libv8 (8.4.255.0-x86_64-darwin-19)
@@ -1081,7 +507,7 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
G
- simulate_platform("x86_64-darwin-19") { bundle "lock --update" }
+ simulate_platform(Gem::Platform.new("x86_64-darwin-19")) { bundle "lock --update" }
expect(out).to match(/Writing lockfile to.+Gemfile\.lock/)
end
@@ -1098,32 +524,26 @@ RSpec.describe "bundle lock" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "libv8"
G
- simulate_platform("x86_64-darwin-19") { bundle "lock" }
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-19"
- c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-20"
- end
+ simulate_platform(Gem::Platform.new("x86_64-darwin")) { bundle "lock" }
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
libv8 (8.4.255.0-x86_64-darwin-19)
libv8 (8.4.255.0-x86_64-darwin-20)
PLATFORMS
- x86_64-darwin-19
- x86_64-darwin-20
+ x86_64-darwin
DEPENDENCIES
libv8
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1140,20 +560,15 @@ RSpec.describe "bundle lock" do
end
end
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-19"
- c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-20"
- end
-
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "libv8"
G
lockfile <<-G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
libv8 (8.4.255.0-x86_64-darwin-19)
libv8 (8.4.255.0-x86_64-darwin-20)
@@ -1163,7 +578,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
libv8
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1171,7 +586,7 @@ RSpec.describe "bundle lock" do
previous_lockfile = lockfile
%w[x86_64-darwin-19 x86_64-darwin-20].each do |platform|
- simulate_platform(platform) do
+ simulate_platform(Gem::Platform.new(platform)) do
bundle "lock"
expect(lockfile).to eq(previous_lockfile)
@@ -1205,14 +620,14 @@ RSpec.describe "bundle lock" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
gem "raygun-apm"
G
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
raygun-apm (1.0.78-universal-darwin)
@@ -1226,117 +641,7 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
L
- bundle "lock --add-platform x86_64-linux"
- end
-
- it "adds platform specific gems as necessary, even when adding the current platform" do
- build_repo4 do
- build_gem "nokogiri", "1.16.0"
-
- build_gem "nokogiri", "1.16.0" do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
-
- gem "nokogiri"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.16.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- simulate_platform "x86_64-linux" do
- bundle "lock --add-platform x86_64-linux"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.16.0)
- nokogiri (1.16.0-x86_64-linux)
-
- PLATFORMS
- ruby
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "does not crash on conflicting ruby requirements between platform versions in two different gems" do
- build_repo4 do
- build_gem "unf_ext", "0.0.8.2"
-
- build_gem "unf_ext", "0.0.8.2" do |s|
- s.required_ruby_version = [">= 2.4", "< #{previous_ruby_minor}"]
- s.platform = "x64-mingw32"
- end
-
- build_gem "unf_ext", "0.0.8.2" do |s|
- s.required_ruby_version = [">= #{previous_ruby_minor}", "< #{current_ruby_minor}"]
- s.platform = "x64-mingw-ucrt"
- end
-
- build_gem "google-protobuf", "3.21.12"
-
- build_gem "google-protobuf", "3.21.12" do |s|
- s.required_ruby_version = [">= 2.5", "< #{previous_ruby_minor}"]
- s.platform = "x64-mingw32"
- end
-
- build_gem "google-protobuf", "3.21.12" do |s|
- s.required_ruby_version = [">= #{previous_ruby_minor}", "< #{current_ruby_minor}"]
- s.platform = "x64-mingw-ucrt"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "google-protobuf"
- gem "unf_ext"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- google-protobuf (3.21.12)
- unf_ext (0.0.8.2)
-
- PLATFORMS
- x64-mingw-ucrt
- x64-mingw32
-
- DEPENDENCIES
- google-protobuf
- unf_ext
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "DEBUG_RESOLVER" => "1" }
+ bundle "lock --add-platform x86_64-linux", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end
it "respects lower bound ruby requirements" do
@@ -1368,123 +673,30 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
L
- bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ bundle "install", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end
context "when an update is available" do
+ let(:repo) { gem_repo2 }
+
before do
- update_repo4 do
+ lockfile(@lockfile)
+ build_repo2 do
build_gem "foo", "2.0"
end
-
- lockfile(expected_lockfile)
end
it "does not implicitly update" do
bundle "lock"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.2"
- c.checksum gem_repo4, "actionpack", "2.3.2"
- c.checksum gem_repo4, "activerecord", "2.3.2"
- c.checksum gem_repo4, "activeresource", "2.3.2"
- c.checksum gem_repo4, "activesupport", "2.3.2"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.2"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
-
- expected_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- 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 (= #{rake_version})
- rake (#{rake_version})
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- rails
- weakling
- #{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"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.2"
- c.checksum gem_repo4, "actionpack", "2.3.2"
- c.checksum gem_repo4, "activerecord", "2.3.2"
- c.checksum gem_repo4, "activeresource", "2.3.2"
- c.checksum gem_repo4, "activesupport", "2.3.2"
- c.checksum gem_repo4, "foo", "2.0"
- c.checksum gem_repo4, "rails", "2.3.2"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
-
- expected_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- 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 (= #{rake_version})
- rake (#{rake_version})
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo (= 2.0)
- rails
- weakling
- #{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
@@ -1498,8 +710,8 @@ RSpec.describe "bundle lock" do
build_gem "irb", "1.5.0"
end
- system_gems "irb-1.5.0", gem_repo: gem_repo4
- system_gems "debug-1.6.3", gem_repo: gem_repo4
+ system_gems "irb-1.5.0", :gem_repo => gem_repo4
+ system_gems "debug-1.6.3", :gem_repo => gem_repo4
# simulate gemspec with wrong empty dependencies
debug_gemspec_path = system_gem_path("specifications/debug-1.6.3.gemspec")
@@ -1510,19 +722,14 @@ RSpec.describe "bundle lock" do
it "respects the existing lockfile, even when reresolving" do
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "debug"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "debug", "1.6.3"
- c.checksum gem_repo4, "irb", "1.5.0"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
debug (1.6.3)
irb (>= 1.3.6)
@@ -1533,7 +740,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
debug
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1544,7 +751,7 @@ RSpec.describe "bundle lock" do
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
debug (1.6.3)
irb (>= 1.3.6)
@@ -1556,7 +763,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
debug
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1583,13 +790,13 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "rails", ">= 7.0.3.1"
gem "activeadmin", "2.13.1"
G
- bundle "lock", raise_on_error: false
+ bundle "lock", :raise_on_error => false
expect(err).to eq <<~ERR.strip
Could not find compatible versions
@@ -1597,7 +804,7 @@ RSpec.describe "bundle lock" do
Because rails >= 7.0.4 depends on railties = 7.0.4
and rails < 7.0.4 depends on railties = 7.0.3.1,
railties = 7.0.3.1 OR = 7.0.4 is required.
- So, because railties = 7.0.3.1 OR = 7.0.4 could not be found in rubygems repository https://gem.repo4/ or installed locally,
+ So, because railties = 7.0.3.1 OR = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally,
version solving has failed.
ERR
end
@@ -1638,7 +845,7 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "rails", ">= 7.0.2.3"
gem "activeadmin", "= 2.13.1"
@@ -1646,7 +853,7 @@ RSpec.describe "bundle lock" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
activeadmin (2.13.1)
ransack (= 3.1.0)
@@ -1654,7 +861,7 @@ RSpec.describe "bundle lock" do
activemodel (>= 6.0.4)
PLATFORMS
- #{local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activeadmin (= 2.13.1)
@@ -1664,34 +871,31 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
L
- expected_error = <<~ERR.strip
+ bundle "lock", :raise_on_error => false
+
+ expect(err).to eq <<~ERR.strip
Could not find compatible versions
- Because rails >= 7.0.4 depends on activemodel = 7.0.4
- and rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1,
- rails >= 7.0.3.1 requires activemodel = 7.0.3.1 OR = 7.0.4.
- (1) So, because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3
- and every version of activemodel depends on activesupport = 6.0.4,
- rails >= 7.0.2.3 requires activesupport = 6.0.4.
+ Because every version of activemodel depends on activesupport = 6.0.4
+ and rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3,
+ every version of activemodel is incompatible with rails >= 7.0.2.3, < 7.0.3.1.
+ And because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3,
+ rails >= 7.0.2.3, < 7.0.3.1 is forbidden.
+ (1) So, because rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1
+ and rails >= 7.0.4 depends on activemodel = 7.0.4,
+ rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4.
- Because rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3
+ Because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3
and rails >= 7.0.3.1, < 7.0.4 depends on activesupport = 7.0.3.1,
- rails >= 7.0.2.3, < 7.0.4 requires activesupport = 7.0.2.3 OR = 7.0.3.1.
- And because rails >= 7.0.4 depends on activesupport = 7.0.4,
- rails >= 7.0.2.3 requires activesupport = 7.0.2.3 OR = 7.0.3.1 OR = 7.0.4.
- And because rails >= 7.0.2.3 requires activesupport = 6.0.4 (1),
- rails >= 7.0.2.3 cannot be used.
+ rails >= 7.0.2.3, < 7.0.4 requires activemodel = 7.0.2.3 or activesupport = 7.0.3.1.
+ And because rails >= 7.0.4 depends on activesupport = 7.0.4
+ and every version of activemodel depends on activesupport = 6.0.4,
+ activemodel != 7.0.2.3 is incompatible with rails >= 7.0.2.3.
+ And because rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4 (1),
+ rails >= 7.0.2.3 is forbidden.
So, because Gemfile depends on rails >= 7.0.2.3,
version solving has failed.
ERR
-
- bundle "lock", raise_on_error: false
- expect(err).to eq(expected_error)
-
- lockfile lockfile.gsub(/PLATFORMS\n #{local_platform}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}")
-
- bundle "lock", raise_on_error: false
- expect(err).to eq(expected_error)
end
it "does not accidentally resolves to prereleases" do
@@ -1711,7 +915,7 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "autoproj", ">= 2.0.0"
G
@@ -1720,31 +924,6 @@ RSpec.describe "bundle lock" do
expect(lockfile).to include("autobuild (1.10.1)")
end
- # Newer rails depends on Bundler, while ancient Rails does not. Bundler tries
- # a first resolution pass that does not consider pre-releases. However, when
- # using a pre-release Bundler (like the .dev version), that results in that
- # pre-release being ignored and resolving to a version that does not depend on
- # Bundler at all. We should avoid that and still consider .dev Bundler.
- #
- it "does not ignore prereleases with there's only one candidate" do
- build_repo4 do
- build_gem "rails", "7.4.0.2" do |s|
- s.add_dependency "bundler", ">= 1.15.0"
- end
-
- build_gem "rails", "2.3.18"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
- gem "rails"
- G
-
- bundle "lock"
- expect(lockfile).to_not include("rails (2.3.18)")
- expect(lockfile).to include("rails (7.4.0.2)")
- end
-
it "deals with platform specific incompatibilities" do
build_repo4 do
build_gem "activerecord", "6.0.6"
@@ -1759,13 +938,13 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "activerecord", "6.0.6"
gem "activerecord-jdbc-adapter", "61.0"
G
simulate_platform "universal-java-19" do
- bundle "lock", raise_on_error: false
+ bundle "lock", :raise_on_error => false
end
expect(err).to include("Could not find compatible versions")
@@ -1785,7 +964,7 @@ RSpec.describe "bundle lock" do
it "does not end up including gems scoped to other platforms in the lockfile" do
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "rails"
gem "tzinfo-data", platform: :windows
G
@@ -1797,277 +976,4 @@ RSpec.describe "bundle lock" do
expect(lockfile).not_to include("tzinfo-data (1.2022.7)")
end
end
-
- context "when resolving platform specific gems as indirect dependencies on truffleruby", :truffleruby_only do
- before do
- build_lib "foo", path: bundled_app do |s|
- s.add_dependency "nokogiri"
- end
-
- build_repo4 do
- build_gem "nokogiri", "1.14.2"
- build_gem "nokogiri", "1.14.2" do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gemspec
- G
- end
-
- it "locks both ruby and platform specific specs" do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo4, "nokogiri", "1.14.2"
- c.checksum gem_repo4, "nokogiri", "1.14.2", "x86_64-linux"
- end
-
- simulate_platform "x86_64-linux" do
- bundle "lock"
- end
-
- expect(lockfile).to eq <<~L
- PATH
- remote: .
- specs:
- foo (1.0)
- nokogiri
-
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.2)
- nokogiri (1.14.2-x86_64-linux)
-
- PLATFORMS
- ruby
- x86_64-linux
-
- DEPENDENCIES
- foo!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- context "and a lockfile with platform specific gems only already exists" do
- before do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo4, "nokogiri", "1.14.2", "x86_64-linux"
- end
-
- lockfile <<~L
- PATH
- remote: .
- specs:
- foo (1.0)
- nokogiri
-
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.2-x86_64-linux)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- foo!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "keeps platform specific gems" do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo4, "nokogiri", "1.14.2"
- c.checksum gem_repo4, "nokogiri", "1.14.2", "x86_64-linux"
- end
-
- simulate_platform "x86_64-linux" do
- bundle "install"
- end
-
- expect(lockfile).to eq <<~L
- PATH
- remote: .
- specs:
- foo (1.0)
- nokogiri
-
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.2)
- nokogiri (1.14.2-x86_64-linux)
-
- PLATFORMS
- ruby
- x86_64-linux
-
- DEPENDENCIES
- foo!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
- end
-
- context "when adding a new gem that requires unlocking other transitive deps" do
- before do
- build_repo4 do
- build_gem "govuk_app_config", "0.1.0"
-
- build_gem "govuk_app_config", "4.13.0" do |s|
- s.add_dependency "railties", ">= 5.0"
- end
-
- %w[7.0.4.1 7.0.4.3].each do |v|
- build_gem "railties", v do |s|
- s.add_dependency "actionpack", v
- s.add_dependency "activesupport", v
- end
-
- build_gem "activesupport", v
- build_gem "actionpack", v
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "govuk_app_config"
- gem "activesupport", "7.0.4.3"
- G
-
- # Simulate out of sync lockfile because top level dependency on
- # activesuport has just been added to the Gemfile, and locked to a higher
- # version
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- actionpack (7.0.4.1)
- activesupport (7.0.4.1)
- govuk_app_config (4.13.0)
- railties (>= 5.0)
- railties (7.0.4.1)
- actionpack (= 7.0.4.1)
- activesupport (= 7.0.4.1)
-
- PLATFORMS
- arm64-darwin-22
-
- DEPENDENCIES
- govuk_app_config
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "does not downgrade top level dependencies" do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "actionpack", "7.0.4.3"
- c.no_checksum "activesupport", "7.0.4.3"
- c.no_checksum "govuk_app_config", "4.13.0"
- c.no_checksum "railties", "7.0.4.3"
- end
-
- simulate_platform "arm64-darwin-22" do
- bundle "lock"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- actionpack (7.0.4.3)
- activesupport (7.0.4.3)
- govuk_app_config (4.13.0)
- railties (>= 5.0)
- railties (7.0.4.3)
- actionpack (= 7.0.4.3)
- activesupport (= 7.0.4.3)
-
- PLATFORMS
- arm64-darwin-22
-
- DEPENDENCIES
- activesupport (= 7.0.4.3)
- govuk_app_config
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- context "when lockfile has incorrectly indented platforms" do
- before do
- build_repo4 do
- build_gem "ffi", "1.1.0" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "ffi", "1.1.0" do |s|
- s.platform = "arm64-darwin"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "ffi"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- ffi (1.1.0-arm64-darwin)
-
- PLATFORMS
- arm64-darwin
-
- DEPENDENCIES
- ffi
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "does not remove any gems" do
- simulate_platform "x86_64-linux" do
- bundle "lock --update"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- ffi (1.1.0-arm64-darwin)
- ffi (1.1.0-x86_64-linux)
-
- PLATFORMS
- arm64-darwin
- x86_64-linux
-
- DEPENDENCIES
- ffi
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
end
diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb
index 668bc0f95e..5827f7380c 100644
--- a/spec/bundler/commands/newgem_spec.rb
+++ b/spec/bundler/commands/newgem_spec.rb
@@ -12,14 +12,14 @@ RSpec.describe "bundle gem" do
def bundle_exec_rubocop
prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec"))
- bundle "config set path #{rubocop_gems}", dir: bundled_app(gem_name)
- bundle "exec rubocop --debug --config .rubocop.yml", dir: bundled_app(gem_name)
+ bundle "config set path #{rubocop_gems}", :dir => bundled_app(gem_name)
+ bundle "exec rubocop --debug --config .rubocop.yml", :dir => bundled_app(gem_name)
end
def bundle_exec_standardrb
prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec"))
- bundle "config set path #{standard_gems}", dir: bundled_app(gem_name)
- bundle "exec standardrb --debug", dir: bundled_app(gem_name)
+ bundle "config set path #{standard_gems}", :dir => bundled_app(gem_name)
+ bundle "exec standardrb --debug", :dir => bundled_app(gem_name)
end
let(:generated_gemspec) { Bundler.load_gemspec_uncached(bundled_app(gem_name).join("#{gem_name}.gemspec")) }
@@ -33,28 +33,25 @@ RSpec.describe "bundle gem" do
let(:minitest_test_class_name) { "class TestMygem < Minitest::Test" }
before do
- git("config --global user.name 'Bundler User'")
- git("config --global user.email user@example.com")
- git("config --global github.user bundleuser")
-
- global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false",
- "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
+ sys_exec("git config --global user.name 'Bundler User'")
+ sys_exec("git config --global user.email user@example.com")
+ sys_exec("git config --global github.user bundleuser")
end
describe "git repo initialization" do
- it "generates a gem skeleton with a .git folder" do
+ it "generates a gem skeleton with a .git folder", :readline do
bundle "gem #{gem_name}"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/.git")).to exist
end
- it "generates a gem skeleton with a .git folder when passing --git" do
+ it "generates a gem skeleton with a .git folder when passing --git", :readline do
bundle "gem #{gem_name} --git"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/.git")).to exist
end
- it "generates a gem skeleton without a .git folder when passing --no-git" do
+ it "generates a gem skeleton without a .git folder when passing --no-git", :readline do
bundle "gem #{gem_name} --no-git"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/.git")).not_to exist
@@ -65,10 +62,8 @@ RSpec.describe "bundle gem" do
Dir.mkdir(bundled_app("path with spaces"))
end
- it "properly initializes git repo" do
- skip "path with spaces needs special handling on Windows" if Gem.win_platform?
-
- bundle "gem #{gem_name}", dir: bundled_app("path with spaces")
+ it "properly initializes git repo", :readline do
+ bundle "gem #{gem_name}", :dir => bundled_app("path with spaces")
expect(bundled_app("path with spaces/#{gem_name}/.git")).to exist
end
end
@@ -108,8 +103,8 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/README.md").read).to match(%r{https://github\.com/bundleuser/#{gem_name}/blob/.*/CODE_OF_CONDUCT.md})
end
- it "generates the README with a section for the Code of Conduct, respecting the configured git default branch", git: ">= 2.28.0" do
- git("config --global init.defaultBranch main")
+ it "generates the README with a section for the Code of Conduct, respecting the configured git default branch", :git => ">= 2.28.0" do
+ sys_exec("git config --global init.defaultBranch main")
bundle "gem #{gem_name} --coc"
expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct")
@@ -136,7 +131,7 @@ RSpec.describe "bundle gem" do
before do
bundle "gem #{gem_name} --changelog"
end
- it "generates a gem skeleton with a CHANGELOG" do
+ it "generates a gem skeleton with a CHANGELOG", :readline do
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/CHANGELOG.md")).to exist
end
@@ -146,16 +141,15 @@ RSpec.describe "bundle gem" do
before do
bundle "gem #{gem_name} --no-changelog"
end
- it "generates a gem skeleton without a CHANGELOG" do
+ it "generates a gem skeleton without a CHANGELOG", :readline do
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/CHANGELOG.md")).to_not exist
end
end
shared_examples_for "--rubocop flag" do
- context "is deprecated", bundler: "< 3" do
+ context "is deprecated", :bundler => "< 3" do
before do
- global_config "BUNDLE_GEM__LINTER" => nil
bundle "gem #{gem_name} --rubocop"
end
@@ -185,7 +179,7 @@ RSpec.describe "bundle gem" do
end
shared_examples_for "--no-rubocop flag" do
- context "is deprecated", bundler: "< 3" do
+ context "is deprecated", :bundler => "< 3" do
define_negated_matcher :exclude, :include
before do
@@ -269,11 +263,11 @@ RSpec.describe "bundle gem" do
end
end
- shared_examples_for "--no-linter flag" do
+ shared_examples_for "--linter=none flag" do
define_negated_matcher :exclude, :include
before do
- bundle "gem #{gem_name} --no-linter"
+ bundle "gem #{gem_name} --linter=none"
end
it "generates a gem skeleton without rubocop" do
@@ -309,49 +303,49 @@ RSpec.describe "bundle gem" do
end
end
- it "has no rubocop offenses when using --linter=rubocop flag" do
+ it "has no rubocop offenses when using --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=c and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=c and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext=c --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=c, --test=minitest, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=c, --test=minitest, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext=c --test=minitest --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=c, --test=rspec, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=c, --test=rspec, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext=c --test=rspec --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=c, --test=test-unit, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=c, --test=test-unit, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext=c --test=test-unit --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no standard offenses when using --linter=standard flag" do
+ it "has no standard offenses when using --linter=standard flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --linter=standard"
bundle_exec_standardrb
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=rust and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=rust and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
@@ -360,7 +354,7 @@ RSpec.describe "bundle gem" do
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=rust, --test=minitest, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=rust, --test=minitest, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
@@ -369,7 +363,7 @@ RSpec.describe "bundle gem" do
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=rust, --test=rspec, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=rust, --test=rspec, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
@@ -378,7 +372,7 @@ RSpec.describe "bundle gem" do
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=rust, --test=test-unit, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=rust, --test=test-unit, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
@@ -405,7 +399,7 @@ RSpec.describe "bundle gem" do
end
end
- context "README.md" do
+ context "README.md", :readline do
context "git config github.user present" do
before do
bundle "gem #{gem_name}"
@@ -419,7 +413,7 @@ RSpec.describe "bundle gem" do
context "git config github.user is absent" do
before do
- git("config --global --unset github.user")
+ sys_exec("git config --global --unset github.user")
bundle "gem #{gem_name}"
end
@@ -430,18 +424,18 @@ RSpec.describe "bundle gem" do
end
end
- it "creates a new git repository" do
+ it "creates a new git repository", :readline do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.git")).to exist
end
- context "when git is not available" do
+ context "when git is not available", :readline do
# This spec cannot have `git` available in the test env
before do
load_paths = [lib_dir, spec_dir]
load_path_str = "-I#{load_paths.join(File::PATH_SEPARATOR)}"
- sys_exec "#{Gem.ruby} #{load_path_str} #{bindir.join("bundle")} gem #{gem_name}", env: { "PATH" => "" }
+ sys_exec "#{Gem.ruby} #{load_path_str} #{bindir.join("bundle")} gem #{gem_name}", :env => { "PATH" => "" }
end
it "creates the gem without the need for git" do
@@ -457,24 +451,24 @@ RSpec.describe "bundle gem" do
end
end
- it "generates a valid gemspec", :ruby_repo do
+ it "generates a valid gemspec", :readline, :ruby_repo do
bundle "gem newgem --bin"
prepare_gemspec(bundled_app("newgem", "newgem.gemspec"))
- gems = ["rake-#{rake_version}"]
- path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(base: bundled_app("newgem")) : system_gem_path
- system_gems gems, path: path
- bundle "exec rake build", dir: bundled_app("newgem")
+ gems = ["rake-13.0.1"]
+ path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(:base => bundled_app("newgem")) : system_gem_path
+ system_gems gems, :path => path
+ bundle "exec rake build", :dir => bundled_app("newgem")
expect(last_command.stdboth).not_to include("ERROR")
end
- context "gem naming with relative paths" do
+ context "gem naming with relative paths", :readline do
it "resolves ." do
create_temporary_dir("tmp")
- bundle "gem .", dir: bundled_app("tmp")
+ bundle "gem .", :dir => bundled_app("tmp")
expect(bundled_app("tmp/lib/tmp.rb")).to exist
end
@@ -482,7 +476,7 @@ RSpec.describe "bundle gem" do
it "resolves .." do
create_temporary_dir("temp/empty_dir")
- bundle "gem ..", dir: bundled_app("temp/empty_dir")
+ bundle "gem ..", :dir => bundled_app("temp/empty_dir")
expect(bundled_app("temp/lib/temp.rb")).to exist
end
@@ -490,7 +484,7 @@ RSpec.describe "bundle gem" do
it "resolves relative directory" do
create_temporary_dir("tmp/empty/tmp")
- bundle "gem ../../empty", dir: bundled_app("tmp/empty/tmp")
+ bundle "gem ../../empty", :dir => bundled_app("tmp/empty/tmp")
expect(bundled_app("tmp/empty/lib/empty.rb")).to exist
end
@@ -563,12 +557,8 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/bin/setup")).to exist
expect(bundled_app("#{gem_name}/bin/console")).to exist
-
- unless Gem.win_platform?
- expect(bundled_app("#{gem_name}/bin/setup")).to be_executable
- expect(bundled_app("#{gem_name}/bin/console")).to be_executable
- end
-
+ expect(bundled_app("#{gem_name}/bin/setup")).to be_executable
+ expect(bundled_app("#{gem_name}/bin/console")).to be_executable
expect(bundled_app("#{gem_name}/bin/setup").read).to start_with("#!")
expect(bundled_app("#{gem_name}/bin/console").read).to start_with("#!")
end
@@ -601,8 +591,8 @@ RSpec.describe "bundle gem" do
context "git config user.{name,email} is not set" do
before do
- git("config --global --unset user.name")
- git("config --global --unset user.email")
+ sys_exec("git config --global --unset user.name")
+ sys_exec("git config --global --unset user.email")
bundle "gem #{gem_name}"
end
@@ -643,25 +633,17 @@ RSpec.describe "bundle gem" do
it "does not include the gemspec file in files" do
bundle "gem #{gem_name}"
- bundler_gemspec = Bundler::GemHelper.new(bundled_app(gem_name), gem_name).gemspec
+ bundler_gemspec = Bundler::GemHelper.new(gemspec_dir).gemspec
expect(bundler_gemspec.files).not_to include("#{gem_name}.gemspec")
end
- it "does not include the Gemfile file in files" do
- bundle "gem #{gem_name}"
-
- bundler_gemspec = Bundler::GemHelper.new(bundled_app(gem_name), gem_name).gemspec
-
- expect(bundler_gemspec.files).not_to include("Gemfile")
- end
-
it "runs rake without problems" do
bundle "gem #{gem_name}"
- system_gems ["rake-#{rake_version}"]
+ system_gems ["rake-13.0.1"]
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
task :default do
puts 'SUCCESS'
end
@@ -670,7 +652,7 @@ RSpec.describe "bundle gem" do
file.puts rakefile
end
- sys_exec(rake, dir: bundled_app(gem_name))
+ sys_exec(rake, :dir => bundled_app(gem_name))
expect(out).to include("SUCCESS")
end
@@ -681,9 +663,6 @@ RSpec.describe "bundle gem" do
it "builds exe skeleton" do
expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to exist
- unless Gem.win_platform?
- expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to be_executable
- end
end
it "requires the main file" do
@@ -742,30 +721,6 @@ RSpec.describe "bundle gem" do
end
end
- context "init_gems_rb setting to true" do
- before do
- bundle "config set init_gems_rb true"
- bundle "gem #{gem_name}"
- end
-
- it "generates gems.rb instead of Gemfile" do
- expect(bundled_app("#{gem_name}/gems.rb")).to exist
- expect(bundled_app("#{gem_name}/Gemfile")).to_not exist
- end
- end
-
- context "init_gems_rb setting to false" do
- before do
- bundle "config set init_gems_rb false"
- bundle "gem #{gem_name}"
- end
-
- it "generates Gemfile instead of gems.rb" do
- expect(bundled_app("#{gem_name}/gems.rb")).to_not exist
- expect(bundled_app("#{gem_name}/Gemfile")).to exist
- end
- end
-
context "gem.test setting set to rspec" do
before do
bundle "config set gem.test rspec"
@@ -834,13 +789,17 @@ 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"
- require "minitest/test_task"
+ require "rake/testtask"
- Minitest::TestTask.create
+ Rake::TestTask.new(:test) do |t|
+ t.libs << "test"
+ t.libs << "lib"
+ t.test_files = FileList["test/**/test_*.rb"]
+ end
task default: :test
RAKEFILE
@@ -881,17 +840,6 @@ RSpec.describe "bundle gem" do
end
end
- context "--test parameter set to an invalid value" do
- before do
- bundle "gem #{gem_name} --test=foo", raise_on_error: false
- end
-
- it "fails loudly" do
- expect(last_command).to be_failure
- expect(err).to match(/Expected '--test' to be one of .*; got foo/)
- end
- end
-
context "gem.test setting set to test-unit" do
before do
bundle "config set gem.test test-unit"
@@ -899,7 +847,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"
@@ -918,7 +866,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.test set to rspec and --test with no arguments" do
+ context "gem.test set to rspec and --test with no arguments", :hint_text do
before do
bundle "config set gem.test rspec"
bundle "gem #{gem_name} --test"
@@ -935,12 +883,10 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.test setting set to false and --test with no arguments", :readline do
+ context "gem.test setting set to false and --test with no arguments", :hint_text do
before do
bundle "config set gem.test false"
- bundle "gem #{gem_name} --test" do |input, _, _|
- input.puts
- end
+ bundle "gem #{gem_name} --test"
end
it "asks to generate test files" do
@@ -954,12 +900,9 @@ RSpec.describe "bundle gem" do
it_behaves_like "test framework is absent"
end
- context "gem.test setting not set and --test with no arguments", :readline do
+ context "gem.test setting not set and --test with no arguments", :hint_text do
before do
- global_config "BUNDLE_GEM__TEST" => nil
- bundle "gem #{gem_name} --test" do |input, _, _|
- input.puts
- end
+ bundle "gem #{gem_name} --test"
end
it "asks to generate test files" do
@@ -975,15 +918,6 @@ RSpec.describe "bundle gem" do
it_behaves_like "test framework is absent"
end
- context "gem.test setting set to a test framework and --no-test" do
- before do
- bundle "config set gem.test rspec"
- bundle "gem #{gem_name} --no-test"
- end
-
- it_behaves_like "test framework is absent"
- end
-
context "--ci with no argument" do
it "does not generate any CI config" do
bundle "gem #{gem_name}"
@@ -994,17 +928,29 @@ RSpec.describe "bundle gem" do
end
end
- context "--ci set to github" do
+ context "--ci set to travis" do
it "generates a GitHub Actions config file" do
- bundle "gem #{gem_name} --ci=github"
+ bundle "gem #{gem_name} --ci=travis", :raise_on_error => false
+ expect(err).to include("Support for Travis CI was removed from gem skeleton generator.")
- expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
+ expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
+ end
+ end
+
+ context "--ci set to travis" do
+ it "generates a GitHub Actions config file" do
+ bundle "gem #{gem_name} --ci=travis", :raise_on_error => false
+ expect(err).to include("Support for Travis CI was removed from gem skeleton generator.")
+
+ expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
end
+ end
- it "contained .gitlab-ci.yml into ignore list" do
+ context "--ci set to github" do
+ it "generates a GitHub Actions config file" do
bundle "gem #{gem_name} --ci=github"
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .github appveyor")
+ expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
end
end
@@ -1014,12 +960,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
@@ -1028,23 +968,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 "--ci set to an invalid value" do
- before do
- bundle "gem #{gem_name} --ci=foo", raise_on_error: false
- end
-
- it "fails loudly" do
- expect(last_command).to be_failure
- expect(err).to match(/Expected '--ci' to be one of .*; got foo/)
- end
end
context "gem.ci setting set to none" do
@@ -1055,6 +978,18 @@ RSpec.describe "bundle gem" do
end
end
+ context "gem.ci setting set to travis" do
+ it "errors with friendly message" do
+ bundle "config set gem.ci travis"
+ bundle "gem #{gem_name}", :raise_on_error => false
+
+ expect(err).to include("Support for Travis CI was removed from gem skeleton generator,")
+ expect(err).to include("bundle config unset gem.ci")
+
+ expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
+ end
+ end
+
context "gem.ci setting set to github" do
it "generates a GitHub Actions config file" do
bundle "config set gem.ci github"
@@ -1082,7 +1017,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.ci set to github and --ci with no arguments" do
+ context "gem.ci set to github and --ci with no arguments", :hint_text do
before do
bundle "config set gem.ci github"
bundle "gem #{gem_name} --ci"
@@ -1097,12 +1032,10 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.ci setting set to false and --ci with no arguments", :readline do
+ context "gem.ci setting set to false and --ci with no arguments", :hint_text do
before do
bundle "config set gem.ci false"
- bundle "gem #{gem_name} --ci" do |input, _, _|
- input.puts "github"
- end
+ bundle "gem #{gem_name} --ci"
end
it "asks to setup CI" do
@@ -1114,12 +1047,9 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.ci setting not set and --ci with no arguments", :readline do
+ context "gem.ci setting not set and --ci with no arguments", :hint_text do
before do
- global_config "BUNDLE_GEM__CI" => nil
- bundle "gem #{gem_name} --ci" do |input, _, _|
- input.puts "github"
- end
+ bundle "gem #{gem_name} --ci"
end
it "asks to setup CI" do
@@ -1133,19 +1063,6 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.ci setting set to a CI service and --no-ci" do
- before do
- bundle "config set gem.ci github"
- bundle "gem #{gem_name} --no-ci"
- end
-
- it "does not generate any CI config" do
- expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist
- end
- end
-
context "--linter with no argument" do
it "does not generate any linter config" do
bundle "gem #{gem_name}"
@@ -1173,17 +1090,6 @@ RSpec.describe "bundle gem" do
end
end
- context "--linter set to an invalid value" do
- before do
- bundle "gem #{gem_name} --linter=foo", raise_on_error: false
- end
-
- it "fails loudly" do
- expect(last_command).to be_failure
- expect(err).to match(/Expected '--linter' to be one of .*; got foo/)
- end
- end
-
context "gem.linter setting set to none" do
it "doesn't generate any linter config" do
bundle "gem #{gem_name}"
@@ -1211,9 +1117,8 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.rubocop setting set to true", bundler: "< 3" do
+ context "gem.rubocop setting set to true", :bundler => "< 3" do
before do
- global_config "BUNDLE_GEM__LINTER" => nil
bundle "config set gem.rubocop true"
bundle "gem #{gem_name}"
end
@@ -1233,7 +1138,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.linter set to rubocop and --linter with no arguments" do
+ context "gem.linter set to rubocop and --linter with no arguments", :hint_text do
before do
bundle "config set gem.linter rubocop"
bundle "gem #{gem_name} --linter"
@@ -1248,12 +1153,10 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.linter setting set to false and --linter with no arguments", :readline do
+ context "gem.linter setting set to false and --linter with no arguments", :hint_text do
before do
bundle "config set gem.linter false"
- bundle "gem #{gem_name} --linter" do |input, _, _|
- input.puts "rubocop"
- end
+ bundle "gem #{gem_name} --linter"
end
it "asks to setup a linter" do
@@ -1265,12 +1168,9 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.linter setting not set and --linter with no arguments", :readline do
+ context "gem.linter setting not set and --linter with no arguments", :hint_text do
before do
- global_config "BUNDLE_GEM__LINTER" => nil
- bundle "gem #{gem_name} --linter" do |input, _, _|
- input.puts "rubocop"
- end
+ bundle "gem #{gem_name} --linter"
end
it "asks to setup a linter" do
@@ -1284,18 +1184,6 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.linter setting set to a linter and --no-linter" do
- before do
- bundle "config set gem.linter rubocop"
- bundle "gem #{gem_name} --no-linter"
- end
-
- it "does not generate any linter config" do
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
- end
- end
-
context "--edit option" do
it "opens the generated gemspec in the user's text editor" do
output = bundle "gem #{gem_name} --edit=echo"
@@ -1305,7 +1193,7 @@ RSpec.describe "bundle gem" do
end
end
- context "testing --mit and --coc options against bundle config settings" do
+ context "testing --mit and --coc options against bundle config settings", :readline do
let(:gem_name) { "test-gem" }
let(:require_path) { "test/gem" }
@@ -1348,7 +1236,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
it_behaves_like "--rubocop flag"
it_behaves_like "--no-rubocop flag"
end
@@ -1359,7 +1247,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
it_behaves_like "--rubocop flag"
it_behaves_like "--no-rubocop flag"
end
@@ -1370,7 +1258,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
end
context "with linter option in bundle config settings set to standard" do
@@ -1379,7 +1267,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
end
context "with linter option in bundle config settings set to false" do
@@ -1388,7 +1276,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
end
context "with changelog option in bundle config settings set to true" do
@@ -1408,10 +1296,10 @@ RSpec.describe "bundle gem" do
end
end
- context "testing --github-username option against git and bundle config settings" do
+ context "testing --github-username option against git and bundle config settings", :readline do
context "without git config set" do
before do
- git("config --global --unset github.user")
+ sys_exec("git config --global --unset github.user")
end
context "with github-username option in bundle config settings set to some value" do
before do
@@ -1445,10 +1333,10 @@ RSpec.describe "bundle gem" do
end
end
- context "testing github_username bundle config against git config settings" do
+ context "testing github_username bundle config against git config settings", :readline do
context "without git config set" do
before do
- git("config --global --unset github.user")
+ sys_exec("git config --global --unset github.user")
end
it_behaves_like "github_username configuration"
@@ -1459,7 +1347,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem naming with underscore" do
+ context "gem naming with underscore", :readline do
let(:gem_name) { "test_gem" }
let(:require_path) { "test_gem" }
@@ -1481,7 +1369,7 @@ RSpec.describe "bundle gem" do
include_examples "generating a gem"
context "--ext parameter with no value" do
- context "is deprecated", bundler: "< 3" do
+ context "is deprecated", :bundler => "< 3" do
it "prints deprecation when used after gem name" do
bundle ["gem", "--ext", gem_name].compact.join(" ")
expect(err).to include "[DEPRECATED]"
@@ -1523,7 +1411,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"
@@ -1531,9 +1419,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
@@ -1583,17 +1469,15 @@ 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"
- require "rb_sys/extensiontask"
+ require "rake/extensiontask"
task build: :compile
- GEMSPEC = Gem::Specification.load("#{gem_name}.gemspec")
-
- RbSys::ExtensionTask.new("#{gem_name}", GEMSPEC) do |ext|
+ Rake::ExtensionTask.new("#{gem_name}") do |ext|
ext.lib_dir = "lib/#{gem_name}"
end
@@ -1605,7 +1489,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem naming with dashed" do
+ context "gem naming with dashed", :readline do
let(:gem_name) { "test-gem" }
let(:require_path) { "test/gem" }
@@ -1626,29 +1510,29 @@ RSpec.describe "bundle gem" do
end
describe "uncommon gem names" do
- it "can deal with two dashes" do
+ it "can deal with two dashes", :readline do
bundle "gem a--a"
expect(bundled_app("a--a/a--a.gemspec")).to exist
end
it "fails gracefully with a ." do
- bundle "gem foo.gemspec", raise_on_error: false
+ bundle "gem foo.gemspec", :raise_on_error => false
expect(err).to end_with("Invalid gem name foo.gemspec -- `Foo.gemspec` is an invalid constant name")
end
it "fails gracefully with a ^" do
- bundle "gem ^", raise_on_error: false
+ bundle "gem ^", :raise_on_error => false
expect(err).to end_with("Invalid gem name ^ -- `^` is an invalid constant name")
end
it "fails gracefully with a space" do
- bundle "gem 'foo bar'", raise_on_error: false
+ bundle "gem 'foo bar'", :raise_on_error => false
expect(err).to end_with("Invalid gem name foo bar -- `Foo bar` is an invalid constant name")
end
it "fails gracefully when multiple names are passed" do
- bundle "gem foo bar baz", raise_on_error: false
+ bundle "gem foo bar baz", :raise_on_error => false
expect(err).to eq(<<-E.strip)
ERROR: "bundle gem" was called with arguments ["foo", "bar", "baz"]
Usage: "bundle gem NAME [OPTIONS]"
@@ -1656,9 +1540,9 @@ Usage: "bundle gem NAME [OPTIONS]"
end
end
- describe "#ensure_safe_gem_name" do
+ describe "#ensure_safe_gem_name", :readline do
before do
- bundle "gem #{subject}", raise_on_error: false
+ bundle "gem #{subject}", :raise_on_error => false
end
context "with an existing const name" do
@@ -1684,14 +1568,14 @@ Usage: "bundle gem NAME [OPTIONS]"
context "on first run", :readline do
it "asks about test framework" do
- global_config "BUNDLE_GEM__TEST" => nil
+ global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "rspec"
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"
@@ -1707,7 +1591,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CI service" do
- global_config "BUNDLE_GEM__CI" => nil
+ global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "github"
@@ -1717,7 +1601,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about MIT license" do
- global_config "BUNDLE_GEM__MIT" => nil
+ global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "config list"
@@ -1729,7 +1613,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CoC" do
- global_config "BUNDLE_GEM__COC" => nil
+ global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "yes"
@@ -1739,7 +1623,8 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CHANGELOG" do
- global_config "BUNDLE_GEM__CHANGELOG" => nil
+ global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false",
+ "BUNDLE_GEM__COC" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "yes"
@@ -1749,16 +1634,16 @@ Usage: "bundle gem NAME [OPTIONS]"
end
end
- context "on conflicts with a previously created file" do
+ context "on conflicts with a previously created file", :readline do
it "should fail gracefully" do
FileUtils.touch(bundled_app("conflict-foobar"))
- bundle "gem conflict-foobar", raise_on_error: false
+ bundle "gem conflict-foobar", :raise_on_error => false
expect(err).to eq("Couldn't create a new gem named `conflict-foobar` because there's an existing file named `conflict-foobar`.")
expect(exitstatus).to eql(32)
end
end
- context "on conflicts with a previously created directory" do
+ context "on conflicts with a previously created directory", :readline do
it "should succeed" do
FileUtils.mkdir_p(bundled_app("conflict-foobar/Gemfile"))
bundle "gem conflict-foobar"
diff --git a/spec/bundler/commands/open_spec.rb b/spec/bundler/commands/open_spec.rb
index e0c79aa407..e30ebfea5b 100644
--- a/spec/bundler/commands/open_spec.rb
+++ b/spec/bundler/commands/open_spec.rb
@@ -4,33 +4,33 @@ RSpec.describe "bundle open" do
context "when opening a regular gem" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
end
it "opens the gem with BUNDLER_EDITOR as highest priority" do
- bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
expect(out).to include("bundler_editor #{default_bundle_path("gems", "rails-2.3.2")}")
end
it "opens the gem with VISUAL as 2nd highest priority" do
- bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "" }
expect(out).to include("visual #{default_bundle_path("gems", "rails-2.3.2")}")
end
it "opens the gem with EDITOR as 3rd highest priority" do
- bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "rails-2.3.2")}")
end
it "complains if no EDITOR is set" do
- bundle "open rails", env: { "EDITOR" => "", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", :env => { "EDITOR" => "", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to eq("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR")
end
it "complains if gem not in bundle" do
- bundle "open missing", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open missing", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to match(/could not find gem 'missing'/i)
end
@@ -39,113 +39,113 @@ RSpec.describe "bundle open" do
ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{lib_path("foo-1.0")}"
G
- bundle "open foo", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
- expect(out).to include("editor #{default_bundle_path("bundler", "gems", "foo-1.0-#{ref}")}")
+ bundle "open foo", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ expect(out).to match("editor #{default_bundle_path.join("bundler/gems/foo-1.0-#{ref}")}")
end
it "suggests alternatives for similar-sounding gems" do
- bundle "open Rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open Rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to match(/did you mean rails\?/i)
end
it "opens the gem with short words" do
- bundle "open rec", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open rec", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2")}")
end
it "opens subpath of the gem" do
- bundle "open activerecord --path lib/activerecord", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open activerecord --path lib/activerecord", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/activerecord")
end
it "opens subpath file of the gem" do
- bundle "open activerecord --path lib/version.rb", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open activerecord --path lib/version.rb", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/version.rb")
end
it "opens deep subpath of the gem" do
- bundle "open activerecord --path lib/active_record", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open activerecord --path lib/active_record", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/active_record")
end
it "requires value for --path arg" do
- bundle "open activerecord --path", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open activerecord --path", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to eq "Cannot specify `--path` option without a value"
end
it "suggests alternatives for similar-sounding gems when using subpath" do
- bundle "open Rails --path README.md", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open Rails --path README.md", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to match(/did you mean rails\?/i)
end
it "suggests alternatives for similar-sounding gems when using deep subpath" do
- bundle "open Rails --path some/path/here", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open Rails --path some/path/here", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to match(/did you mean rails\?/i)
end
it "opens subpath of the short worded gem" do
- bundle "open rec --path CHANGELOG.md", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rec --path CHANGELOG.md", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/CHANGELOG.md")
end
it "opens deep subpath of the short worded gem" do
- bundle "open rec --path lib/activerecord", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rec --path lib/activerecord", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/activerecord")
end
it "opens subpath of the selected matching gem", :readline do
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active --path CHANGELOG.md", env: env do |input, _, _|
+ bundle "open active --path CHANGELOG.md", :env => env do |input, _, _|
input.puts "2"
end
- expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2").join("CHANGELOG.md")}")
+ 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
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active --path lib/activerecord/version.rb", env: env do |input, _, _|
+ bundle "open active --path lib/activerecord/version.rb", :env => env do |input, _, _|
input.puts "2"
end
- expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2").join("lib", "activerecord", "version.rb")}")
+ 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
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active", env: env do |input, _, _|
+ bundle "open active", :env => env do |input, _, _|
input.puts "2"
end
- expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2")}")
+ 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
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active", env: env do |input, _, _|
+ bundle "open active", :env => env do |input, _, _|
input.puts "0"
end
end
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
gem "foo"
G
bundle "config set auto_install 1"
- bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("Installing foo 1.0")
end
it "opens the editor with a clean env" do
- bundle "open", env: { "EDITOR" => "sh -c 'env'", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open", :env => { "EDITOR" => "sh -c 'env'", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(out).not_to include("BUNDLE_GEMFILE=")
end
end
@@ -163,12 +163,13 @@ RSpec.describe "bundle open" do
skip "No default gems available on this test run" if default_gems.empty?
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "json"
G
end
it "throws proper error when trying to open default gem" do
- bundle "open json", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open json", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
expect(out).to include("Unable to open json because it's a default gem, so the directory it would normally be installed to does not exist.")
end
end
diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb
index 449fba5935..e084af85d7 100644
--- a/spec/bundler/commands/outdated_spec.rb
+++ b/spec/bundler/commands/outdated_spec.rb
@@ -4,12 +4,12 @@ RSpec.describe "bundle outdated" do
describe "with no arguments" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -23,11 +23,11 @@ RSpec.describe "bundle outdated" do
update_repo2 do
build_gem "activesupport", "3.0"
build_gem "weakling", "0.2"
- update_git "foo", path: lib_path("foo")
- update_git "zebra", path: lib_path("zebra")
+ update_git "foo", :path => lib_path("foo")
+ update_git "zebra", :path => lib_path("zebra")
end
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -46,11 +46,11 @@ RSpec.describe "bundle outdated" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "AAA", "1.0.0"
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE
Gem Current Latest Requested Groups
@@ -63,10 +63,10 @@ RSpec.describe "bundle outdated" do
it "returns non zero exit status if outdated gems present" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expect(exitstatus).to_not be_zero
end
@@ -77,7 +77,7 @@ RSpec.describe "bundle outdated" do
it "adds gem group to dependency output when repo is updated" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "terranova", '8'
@@ -89,7 +89,7 @@ RSpec.describe "bundle outdated" do
update_repo2 { build_gem "activesupport", "3.0" }
update_repo2 { build_gem "terranova", "9" }
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -104,12 +104,12 @@ RSpec.describe "bundle outdated" do
describe "with --verbose option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -126,20 +126,20 @@ RSpec.describe "bundle outdated" do
update_repo2 { build_gem "terranova", "9" }
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "terranova", '9'
gem 'activesupport', '2.3.5'
G
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "terranova", '8'
gem 'activesupport', '2.3.5'
G
- bundle "outdated --verbose", raise_on_error: false
+ bundle "outdated --verbose", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups Path
@@ -151,7 +151,7 @@ RSpec.describe "bundle outdated" do
end
end
- describe "with multiple, duplicated sources, with lockfile in old format", bundler: "< 3" do
+ describe "with multiple, duplicated sources, with lockfile in old format", :bundler => "< 3" do
before do
build_repo2 do
build_gem "dotenv", "2.7.6"
@@ -162,7 +162,7 @@ RSpec.describe "bundle outdated" do
build_gem "vcr", "6.0.0"
end
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s|
s.add_dependency "oj"
end
@@ -192,7 +192,7 @@ RSpec.describe "bundle outdated" do
vcr (6.0.0)
PLATFORMS
- #{local_platform}
+ #{specific_local_platform}
DEPENDENCIES
dotenv
@@ -205,8 +205,8 @@ RSpec.describe "bundle outdated" do
end
it "works" do
- bundle :install, artifice: "compact_index"
- bundle :outdated, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index"
+ bundle :outdated, :artifice => "compact_index", :raise_on_error => false
expected_output = <<~TABLE
Gem Current Latest Requested Groups
@@ -220,12 +220,12 @@ RSpec.describe "bundle outdated" do
describe "with --group option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling", "~> 0.0.1"
gem "terranova", '8'
@@ -243,7 +243,7 @@ RSpec.describe "bundle outdated" do
build_gem "duradura", "8.0"
end
- bundle "outdated --group #{group}", raise_on_error: false
+ bundle "outdated --group #{group}", :raise_on_error => false
end
it "works when the bundle is up to date" do
@@ -251,14 +251,6 @@ RSpec.describe "bundle outdated" do
expect(out).to end_with("Bundle up to date!")
end
- it "works when only out of date gems are not in given group" do
- update_repo2 do
- build_gem "terranova", "9"
- end
- bundle "outdated --group development"
- expect(out).to end_with("Bundle up to date!")
- end
-
it "returns a sorted list of outdated gems from one group => 'default'" do
test_group_option("default")
@@ -298,8 +290,8 @@ RSpec.describe "bundle outdated" do
describe "with --groups option and outdated transitive dependencies" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
build_gem "bar", %w[2.0.0]
@@ -309,7 +301,7 @@ RSpec.describe "bundle outdated" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "bar_dependant", '7.0'
G
@@ -320,7 +312,7 @@ RSpec.describe "bundle outdated" do
end
it "returns a sorted list of outdated gems" do
- bundle "outdated --groups", raise_on_error: false
+ bundle "outdated --groups", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -334,12 +326,12 @@ RSpec.describe "bundle outdated" do
describe "with --groups option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling", "~> 0.0.1"
gem "terranova", '8'
@@ -362,7 +354,7 @@ RSpec.describe "bundle outdated" do
build_gem "duradura", "8.0"
end
- bundle "outdated --groups", raise_on_error: false
+ bundle "outdated --groups", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -378,12 +370,12 @@ RSpec.describe "bundle outdated" do
describe "with --local option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling", "~> 0.0.1"
gem "terranova", '8'
@@ -402,11 +394,11 @@ RSpec.describe "bundle outdated" do
bundle "config set clean false"
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.4"
G
- bundle "outdated --local", raise_on_error: false
+ bundle "outdated --local", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -428,15 +420,15 @@ RSpec.describe "bundle outdated" do
context "and gems are outdated" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
build_gem "activesupport", "3.0"
build_gem "weakling", "0.2"
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -446,51 +438,30 @@ RSpec.describe "bundle outdated" do
G
end
- it "outputs a sorted list of outdated gems with a more minimal format to stdout" do
+ it "outputs a sorted list of outdated gems with a more minimal format" do
minimal_output = "activesupport (newest 3.0, installed 2.3.5, requested = 2.3.5)\n" \
"weakling (newest 0.2, installed 0.0.3, requested ~> 0.0.1)"
subject
expect(out).to eq(minimal_output)
end
-
- it "outputs progress to stderr" do
- subject
- expect(err).to include("Fetching gem metadata")
- end
end
context "and no gems are outdated" do
- before do
- build_repo2 do
- build_gem "activesupport", "3.0"
- end
-
- install_gemfile <<-G
- source "https://gem.repo2"
- gem "activesupport", "3.0"
- G
- end
-
- it "does not output to stdout" do
+ it "has empty output" do
subject
expect(out).to be_empty
end
-
- it "outputs progress to stderr" do
- subject
- expect(err).to include("Fetching gem metadata")
- end
end
end
describe "with --parseable option" do
- subject { bundle "outdated --parseable", raise_on_error: false }
+ subject { bundle "outdated --parseable", :raise_on_error => false }
it_behaves_like "a minimal output is desired"
end
describe "with aliased --porcelain option" do
- subject { bundle "outdated --porcelain", raise_on_error: false }
+ subject { bundle "outdated --porcelain", :raise_on_error => false }
it_behaves_like "a minimal output is desired"
end
@@ -498,12 +469,12 @@ RSpec.describe "bundle outdated" do
describe "with specified gems" do
it "returns list of outdated gems" do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -514,10 +485,10 @@ RSpec.describe "bundle outdated" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
- bundle "outdated foo", raise_on_error: false
+ bundle "outdated foo", :raise_on_error => false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -531,12 +502,12 @@ RSpec.describe "bundle outdated" do
describe "pre-release gems" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -564,7 +535,7 @@ RSpec.describe "bundle outdated" do
build_gem "activesupport", "3.0.0.beta"
end
- bundle "outdated --pre", raise_on_error: false
+ bundle "outdated --pre", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -583,11 +554,11 @@ RSpec.describe "bundle outdated" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "3.0.0.beta.1"
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -602,12 +573,12 @@ RSpec.describe "bundle outdated" do
describe "with --filter-strict option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -623,7 +594,7 @@ RSpec.describe "bundle outdated" do
build_gem "weakling", "0.0.5"
end
- bundle :outdated, "filter-strict": true, raise_on_error: false
+ bundle :outdated, :"filter-strict" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -639,7 +610,7 @@ RSpec.describe "bundle outdated" do
build_gem "weakling", "0.0.5"
end
- bundle :outdated, strict: true, raise_on_error: false
+ bundle :outdated, :strict => true, :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -651,22 +622,22 @@ RSpec.describe "bundle outdated" do
it "doesn't crash when some deps unused on the current platform" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", platforms: [:ruby_22]
G
- bundle :outdated, "filter-strict": true
+ bundle :outdated, :"filter-strict" => true
expect(out).to end_with("Bundle up to date!")
end
it "only reports gem dependencies when they can actually be updated" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack_middleware", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack_middleware", "1.0"
G
- bundle :outdated, "filter-strict": true
+ bundle :outdated, :"filter-strict" => true
expect(out).to end_with("Bundle up to date!")
end
@@ -674,7 +645,7 @@ RSpec.describe "bundle outdated" do
describe "and filter options" do
it "only reports gems that match requirement and patch filter level" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "~> 2.3"
gem "weakling", ">= 0.0.1"
G
@@ -696,7 +667,7 @@ RSpec.describe "bundle outdated" do
it "only reports gems that match requirement and minor filter level" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "~> 2.3"
gem "weakling", ">= 0.0.1"
G
@@ -718,7 +689,7 @@ RSpec.describe "bundle outdated" do
it "only reports gems that match requirement and major filter level" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "~> 2.3"
gem "weakling", ">= 0.0.1"
G
@@ -743,12 +714,12 @@ RSpec.describe "bundle outdated" do
describe "with invalid gem name" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -759,46 +730,46 @@ RSpec.describe "bundle outdated" do
end
it "returns could not find gem name" do
- bundle "outdated invalid_gem_name", raise_on_error: false
+ bundle "outdated invalid_gem_name", :raise_on_error => false
expect(err).to include("Could not find gem 'invalid_gem_name'.")
end
it "returns non-zero exit code" do
- bundle "outdated invalid_gem_name", raise_on_error: false
+ bundle "outdated invalid_gem_name", :raise_on_error => false
expect(exitstatus).to_not be_zero
end
end
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
gem "foo"
G
bundle "config set auto_install 1"
- bundle :outdated, raise_on_error: false
+ bundle :outdated, :raise_on_error => false
expect(out).to include("Installing foo 1.0")
end
- context "after bundle install --deployment", bundler: "< 3" do
+ context "after bundle install --deployment", :bundler => "< 3" do
before do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
gem "foo"
G
bundle :lock
- bundle :install, deployment: true
+ bundle :install, :deployment => true
end
it "outputs a helpful message about being in deployment mode" do
update_repo2 { build_gem "activesupport", "3.0" }
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("You are trying to check outdated gems in deployment mode.")
expect(err).to include("Run `bundle outdated` elsewhere.")
@@ -810,14 +781,14 @@ RSpec.describe "bundle outdated" do
context "after bundle config set --local deployment true" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
gem "foo"
G
bundle "config set --local deployment true"
@@ -826,7 +797,7 @@ RSpec.describe "bundle outdated" do
it "outputs a helpful message about being in deployment mode" do
update_repo2 { build_gem "activesupport", "3.0" }
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("You are trying to check outdated gems in deployment mode.")
expect(err).to include("Run `bundle outdated` elsewhere.")
@@ -840,7 +811,7 @@ RSpec.describe "bundle outdated" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "laduradura", '= 5.15.2'
G
end
@@ -858,7 +829,7 @@ RSpec.describe "bundle outdated" do
it "reports that updates are available if the Ruby platform is used" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "laduradura", '= 5.15.2', :platforms => [:ruby, :jruby]
G
@@ -868,11 +839,11 @@ RSpec.describe "bundle outdated" do
it "reports that updates are available if the JRuby platform is used", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "laduradura", '= 5.15.2', :platforms => [:ruby, :jruby]
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -896,12 +867,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "major version updates are detected" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -922,12 +893,12 @@ RSpec.describe "bundle outdated" do
context "when on a new machine" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -938,26 +909,26 @@ RSpec.describe "bundle outdated" do
simulate_new_machine
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
update_repo2 do
build_gem "activesupport", "3.3.5"
build_gem "weakling", "0.8.0"
end
end
- subject { bundle "outdated", raise_on_error: false }
+ subject { bundle "outdated", :raise_on_error => false }
it_behaves_like "version update is detected"
end
shared_examples_for "minor version updates are detected" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -978,12 +949,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "patch version updates are detected" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -1011,12 +982,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "major version is ignored" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -1037,12 +1008,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "minor version is ignored" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -1063,12 +1034,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "patch version is ignored" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -1087,7 +1058,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major option" do
- subject { bundle "outdated --filter-major", raise_on_error: false }
+ subject { bundle "outdated --filter-major", :raise_on_error => false }
it_behaves_like "major version updates are detected"
it_behaves_like "minor version is ignored"
@@ -1095,7 +1066,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-minor option" do
- subject { bundle "outdated --filter-minor", raise_on_error: false }
+ subject { bundle "outdated --filter-minor", :raise_on_error => false }
it_behaves_like "minor version updates are detected"
it_behaves_like "major version is ignored"
@@ -1103,7 +1074,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-patch option" do
- subject { bundle "outdated --filter-patch", raise_on_error: false }
+ subject { bundle "outdated --filter-patch", :raise_on_error => false }
it_behaves_like "patch version updates are detected"
it_behaves_like "major version is ignored"
@@ -1111,7 +1082,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-minor --filter-patch options" do
- subject { bundle "outdated --filter-minor --filter-patch", raise_on_error: false }
+ subject { bundle "outdated --filter-minor --filter-patch", :raise_on_error => false }
it_behaves_like "minor version updates are detected"
it_behaves_like "patch version updates are detected"
@@ -1119,7 +1090,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major --filter-minor options" do
- subject { bundle "outdated --filter-major --filter-minor", raise_on_error: false }
+ subject { bundle "outdated --filter-major --filter-minor", :raise_on_error => false }
it_behaves_like "major version updates are detected"
it_behaves_like "minor version updates are detected"
@@ -1127,7 +1098,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major --filter-patch options" do
- subject { bundle "outdated --filter-major --filter-patch", raise_on_error: false }
+ subject { bundle "outdated --filter-major --filter-patch", :raise_on_error => false }
it_behaves_like "major version updates are detected"
it_behaves_like "patch version updates are detected"
@@ -1135,7 +1106,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major --filter-minor --filter-patch options" do
- subject { bundle "outdated --filter-major --filter-minor --filter-patch", raise_on_error: false }
+ subject { bundle "outdated --filter-major --filter-minor --filter-patch", :raise_on_error => false }
it_behaves_like "major version updates are detected"
it_behaves_like "minor version updates are detected"
@@ -1152,7 +1123,7 @@ RSpec.describe "bundle outdated" do
# establish a lockfile set to 1.0.0
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'patch', '1.0.0'
gem 'minor', '1.0.0'
gem 'major', '1.0.0'
@@ -1160,7 +1131,7 @@ RSpec.describe "bundle outdated" do
# remove all version requirements
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'patch'
gem 'minor'
gem 'major'
@@ -1174,7 +1145,7 @@ RSpec.describe "bundle outdated" do
end
it "shows all gems when patching and filtering to patch" do
- bundle "outdated --patch --filter-patch", raise_on_error: false
+ bundle "outdated --patch --filter-patch", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1187,7 +1158,7 @@ RSpec.describe "bundle outdated" do
end
it "shows minor and major when updating to minor and filtering to patch and minor" do
- bundle "outdated --minor --filter-minor", raise_on_error: false
+ bundle "outdated --minor --filter-minor", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1199,7 +1170,7 @@ RSpec.describe "bundle outdated" do
end
it "shows minor when updating to major and filtering to minor with parseable" do
- bundle "outdated --major --filter-minor --parseable", raise_on_error: false
+ bundle "outdated --major --filter-minor --parseable", :raise_on_error => false
expect(out).not_to include("patch (newest")
expect(out).to include("minor (newest")
@@ -1225,7 +1196,7 @@ RSpec.describe "bundle outdated" do
# establish a lockfile set to 1.4.3
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo', '1.4.3'
gem 'bar', '2.0.3'
gem 'qux', '1.0.0'
@@ -1234,14 +1205,14 @@ RSpec.describe "bundle outdated" do
# remove 1.4.3 requirement and bar altogether
# to setup update specs below
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo'
gem 'qux'
G
end
it "shows gems updating to patch and filtering to patch" do
- bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG_RESOLVER" => "1" }
+ bundle "outdated --patch --filter-patch", :raise_on_error => false, :env => { "DEBUG_RESOLVER" => "1" }
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1253,7 +1224,7 @@ RSpec.describe "bundle outdated" do
end
it "shows gems updating to patch and filtering to patch, in debug mode" do
- bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG" => "1" }
+ bundle "outdated --patch --filter-patch", :raise_on_error => false, :env => { "DEBUG" => "1" }
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups Path
@@ -1275,17 +1246,17 @@ RSpec.describe "bundle outdated" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'weakling', '0.2'
gem 'bar', '2.1'
G
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'weakling'
G
- bundle "outdated --only-explicit", raise_on_error: false
+ bundle "outdated --only-explicit", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1312,7 +1283,7 @@ RSpec.describe "bundle outdated" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.11.1)
nokogiri (1.11.1-#{Bundler.local_platform})
@@ -1329,13 +1300,13 @@ RSpec.describe "bundle outdated" do
L
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
G
end
it "reports a single entry per gem" do
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1359,14 +1330,14 @@ RSpec.describe "bundle outdated" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "mini_portile2"
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
mini_portile2 (2.5.2)
net-ftp (~> 0.1)
@@ -1384,7 +1355,7 @@ RSpec.describe "bundle outdated" do
end
it "works" do
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
diff --git a/spec/bundler/commands/platform_spec.rb b/spec/bundler/commands/platform_spec.rb
index 6e0a02bcf0..4e8e3946fe 100644
--- a/spec/bundler/commands/platform_spec.rb
+++ b/spec/bundler/commands/platform_spec.rb
@@ -4,7 +4,7 @@ RSpec.describe "bundle platform" do
context "without flags" do
it "returns all the output" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
#{ruby_version_correct}
@@ -16,7 +16,7 @@ RSpec.describe "bundle platform" do
Your platform is: #{Gem::Platform.local}
Your app has gems that work on these platforms:
-* #{local_platform}
+* #{specific_local_platform}
Your Gemfile specifies a Ruby version requirement:
* ruby #{Gem.ruby_version}
@@ -27,7 +27,7 @@ G
it "returns all the output including the patchlevel" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
#{ruby_version_correct_patchlevel}
@@ -39,7 +39,7 @@ G
Your platform is: #{Gem::Platform.local}
Your app has gems that work on these platforms:
-* #{local_platform}
+* #{specific_local_platform}
Your Gemfile specifies a Ruby version requirement:
* #{Bundler::RubyVersion.system.single_version_string}
@@ -50,7 +50,7 @@ G
it "doesn't print ruby version requirement if it isn't specified" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
@@ -60,7 +60,7 @@ G
Your platform is: #{Gem::Platform.local}
Your app has gems that work on these platforms:
-* #{local_platform}
+* #{specific_local_platform}
Your Gemfile does not specify a Ruby version requirement.
G
@@ -68,7 +68,7 @@ G
it "doesn't match the ruby version requirement" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
#{ruby_version_incorrect}
@@ -80,7 +80,7 @@ G
Your platform is: #{Gem::Platform.local}
Your app has gems that work on these platforms:
-* #{local_platform}
+* #{specific_local_platform}
Your Gemfile specifies a Ruby version requirement:
* ruby #{not_local_ruby_version}
@@ -93,7 +93,7 @@ G
context "--ruby" do
it "returns ruby version when explicit" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.9.3", :engine => 'ruby', :engine_version => '1.9.3'
gem "foo"
@@ -106,7 +106,7 @@ G
it "defaults to MRI" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.9.3"
gem "foo"
@@ -119,7 +119,7 @@ G
it "handles jruby" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine => 'jruby', :engine_version => '1.6.5'
gem "foo"
@@ -132,7 +132,7 @@ G
it "handles rbx" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine => 'rbx', :engine_version => '1.2.4'
gem "foo"
@@ -145,7 +145,7 @@ G
it "handles truffleruby" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "2.5.1", :engine => 'truffleruby', :engine_version => '1.0.0-rc6'
gem "foo"
@@ -158,46 +158,46 @@ G
it "raises an error if engine is used but engine version is not" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine => 'rbx'
gem "foo"
G
- bundle "platform", raise_on_error: false
+ bundle "platform", :raise_on_error => false
expect(exitstatus).not_to eq(0)
end
it "raises an error if engine_version is used but engine is not" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine_version => '1.2.4'
gem "foo"
G
- bundle "platform", raise_on_error: false
+ bundle "platform", :raise_on_error => false
expect(exitstatus).not_to eq(0)
end
it "raises an error if engine version doesn't match ruby version for MRI" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine => 'ruby', :engine_version => '1.2.4'
gem "foo"
G
- bundle "platform", raise_on_error: false
+ bundle "platform", :raise_on_error => false
expect(exitstatus).not_to eq(0)
end
it "should print if no ruby version is specified" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
@@ -209,13 +209,13 @@ G
it "handles when there is a locked requirement" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "< 1.8.7"
G
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -236,12 +236,12 @@ G
it "handles when there is a lockfile with no requirement" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -259,7 +259,7 @@ G
it "handles when there is a requirement in the gemfile" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= 1.8.7"
G
@@ -269,7 +269,7 @@ G
it "handles when there are multiple requirements in the gemfile" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= 1.8.7", "< 2.0.0"
G
@@ -315,8 +315,8 @@ G
context "bundle install" do
it "installs fine when the ruby version matches" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct}
G
@@ -326,8 +326,8 @@ G
it "installs fine with any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct_engineless}
G
@@ -337,8 +337,8 @@ G
it "installs fine when the patchlevel matches" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct_patchlevel}
G
@@ -347,9 +347,9 @@ G
end
it "doesn't install when the ruby version doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_incorrect}
G
@@ -359,9 +359,9 @@ G
end
it "doesn't install when engine doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{engine_incorrect}
G
@@ -371,9 +371,9 @@ G
end
it "doesn't install when engine version doesn't match", :jruby_only do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{engine_version_incorrect}
G
@@ -383,9 +383,9 @@ G
end
it "doesn't install when patchlevel doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
@@ -398,13 +398,13 @@ G
context "bundle check" do
it "checks fine when the ruby version matches" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct}
G
@@ -415,13 +415,13 @@ G
it "checks fine with any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct_engineless}
G
@@ -432,69 +432,69 @@ G
it "fails when ruby version doesn't match" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_incorrect}
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when engine doesn't match" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{engine_incorrect}
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
should_be_engine_incorrect
end
it "fails when engine version doesn't match", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{engine_version_incorrect}
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -504,57 +504,57 @@ G
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
G
end
it "updates successfully when the ruby version matches" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{ruby_version_correct}
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
- bundle "update", all: true
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 3.0"
+ bundle "update", :all => true
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
it "updates fine with any engine", :jruby_only do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{ruby_version_correct_engineless}
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
- bundle "update", all: true
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 3.0"
+ bundle "update", :all => true
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
it "fails when ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{ruby_version_incorrect}
G
@@ -562,15 +562,15 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
+ bundle :update, :all => true, :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when ruby engine doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{engine_incorrect}
G
@@ -578,15 +578,15 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
+ bundle :update, :all => true, :raise_on_error => false
should_be_engine_incorrect
end
it "fails when ruby engine version doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{engine_version_incorrect}
G
@@ -594,14 +594,14 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
+ bundle :update, :all => true, :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
@@ -609,7 +609,7 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
+ bundle :update, :all => true, :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -617,14 +617,14 @@ G
context "bundle info" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
end
it "prints path if ruby version is correct" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{ruby_version_correct}
@@ -636,7 +636,7 @@ G
it "prints path if ruby version is correct for any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{ruby_version_correct_engineless}
@@ -646,46 +646,46 @@ G
expect(out).to eq(default_bundle_path("gems", "rails-2.3.2").to_s)
end
- it "fails if ruby version doesn't match", bundler: "< 3" do
+ it "fails if ruby version doesn't match", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{ruby_version_incorrect}
G
- bundle "show rails", raise_on_error: false
+ bundle "show rails", :raise_on_error => false
should_be_ruby_version_incorrect
end
- it "fails if engine doesn't match", bundler: "< 3" do
+ it "fails if engine doesn't match", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{engine_incorrect}
G
- bundle "show rails", raise_on_error: false
+ bundle "show rails", :raise_on_error => false
should_be_engine_incorrect
end
- it "fails if engine version doesn't match", bundler: "< 3", jruby_only: true do
+ it "fails if engine version doesn't match", :bundler => "< 3", :jruby_only => true do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{engine_version_incorrect}
G
- bundle "show rails", raise_on_error: false
+ bundle "show rails", :raise_on_error => false
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match", bundler: "< 3" do
+ it "fails when patchlevel doesn't match", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
@@ -693,7 +693,7 @@ G
build_gem "activesupport", "3.0"
end
- bundle "show rails", raise_on_error: false
+ bundle "show rails", :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -701,80 +701,80 @@ G
context "bundle cache" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
it "copies the .gem file to vendor/cache when ruby version matches" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_correct}
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "copies the .gem file to vendor/cache when ruby version matches for any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_correct_engineless}
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "fails if the ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails if the engine doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{engine_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_engine_incorrect
end
it "fails if the engine version doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{engine_version_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -782,80 +782,80 @@ G
context "bundle pack" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
it "copies the .gem file to vendor/cache when ruby version matches" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_correct}
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "copies the .gem file to vendor/cache when ruby version matches any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_correct_engineless}
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "fails if the ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails if the engine doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{engine_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_engine_incorrect
end
it "fails if the engine version doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{engine_version_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -863,104 +863,104 @@ G
context "bundle exec" do
before do
ENV["BUNDLER_FORCE_TTY"] = "true"
- system_gems "myrack-1.0.0", "myrack-0.9.1", path: default_bundle_path
+ system_gems "rack-1.0.0", "rack-0.9.1", :path => default_bundle_path
end
it "activates the correct gem when ruby version matches" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
#{ruby_version_correct}
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to include("0.9.1")
end
it "activates the correct gem when ruby version matches any engine", :jruby_only do
- system_gems "myrack-1.0.0", "myrack-0.9.1", path: default_bundle_path
+ system_gems "rack-1.0.0", "rack-0.9.1", :path => default_bundle_path
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
#{ruby_version_correct_engineless}
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to include("0.9.1")
end
it "fails when the ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
#{ruby_version_incorrect}
G
- bundle "exec myrackup", raise_on_error: false
+ bundle "exec rackup", :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when the engine doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
#{engine_incorrect}
G
- bundle "exec myrackup", raise_on_error: false
+ bundle "exec rackup", :raise_on_error => false
should_be_engine_incorrect
end
- it "fails when the engine version doesn't match", :jruby_only do
- gemfile <<-G
- gem "myrack", "0.9.1"
-
- #{engine_version_incorrect}
- G
-
- bundle "exec myrackup", raise_on_error: false
- should_be_engine_version_incorrect
- end
+ # it "fails when the engine version doesn't match", :jruby_only do
+ # gemfile <<-G
+ # gem "rack", "0.9.1"
+ #
+ # #{engine_version_incorrect}
+ # G
+ #
+ # bundle "exec rackup"
+ # should_be_engine_version_incorrect
+ # end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
- bundle "exec myrackup", raise_on_error: false
+ bundle "exec rackup", :raise_on_error => false
should_be_patchlevel_incorrect
end
end
- context "bundle console", bundler: "< 3" do
+ context "bundle console", :bundler => "< 3" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
G
end
it "starts IRB with the default group loaded when ruby version matches", :readline do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{ruby_version_correct}
G
bundle "console" do |input, _, _|
- input.puts("puts MYRACK")
+ input.puts("puts RACK")
input.puts("exit")
end
expect(out).to include("0.9.1")
@@ -968,16 +968,16 @@ G
it "starts IRB with the default group loaded when ruby version matches", :readline, :jruby_only do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{ruby_version_correct_engineless}
G
bundle "console" do |input, _, _|
- input.puts("puts MYRACK")
+ input.puts("puts RACK")
input.puts("exit")
end
expect(out).to include("0.9.1")
@@ -985,57 +985,57 @@ G
it "fails when ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{ruby_version_incorrect}
G
- bundle "console", raise_on_error: false
+ bundle "console", :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when engine doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{engine_incorrect}
G
- bundle "console", raise_on_error: false
+ bundle "console", :raise_on_error => false
should_be_engine_incorrect
end
it "fails when engine version doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{engine_version_incorrect}
G
- bundle "console", raise_on_error: false
+ bundle "console", :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{patchlevel_incorrect}
G
- bundle "console", raise_on_error: false
+ bundle "console", :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -1043,9 +1043,9 @@ G
context "Bundler.setup" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack", :group => :test
+ gem "rack", :group => :test
G
ENV["BUNDLER_FORCE_TTY"] = "true"
@@ -1053,9 +1053,9 @@ G
it "makes a Gemfile.lock if setup succeeds" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{ruby_version_correct}
G
@@ -1068,9 +1068,9 @@ G
it "makes a Gemfile.lock if setup succeeds for any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{ruby_version_correct_engineless}
G
@@ -1082,68 +1082,68 @@ G
end
it "fails when ruby version doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{ruby_version_incorrect}
G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
+ ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
expect(bundled_app_lock).not_to exist
should_be_ruby_version_incorrect
end
it "fails when engine doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{engine_incorrect}
G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
+ ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
expect(bundled_app_lock).not_to exist
should_be_engine_incorrect
end
it "fails when engine version doesn't match", :jruby_only do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{engine_version_incorrect}
G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
+ ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
expect(bundled_app_lock).not_to exist
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{patchlevel_incorrect}
G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
+ ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
expect(bundled_app_lock).not_to exist
should_be_patchlevel_incorrect
@@ -1153,11 +1153,11 @@ G
context "bundle outdated" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
G
@@ -1166,18 +1166,18 @@ G
it "returns list of outdated gems when the ruby version matches" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{ruby_version_correct}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -1192,18 +1192,18 @@ G
bundle :install
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{ruby_version_correct_engineless}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -1217,90 +1217,90 @@ G
it "fails when the ruby version doesn't match" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{ruby_version_incorrect}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when the engine doesn't match" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{engine_incorrect}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_engine_incorrect
end
it "fails when the engine version doesn't match", :jruby_only do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{engine_version_incorrect}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when the patchlevel doesn't match", :jruby_only do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{patchlevel_incorrect}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_patchlevel_incorrect
end
it "fails when the patchlevel is a fixnum", :jruby_only do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{patchlevel_fixnum}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_patchlevel_fixnum
end
end
diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb
index 8671504b25..3050b87754 100644
--- a/spec/bundler/commands/post_bundle_message_spec.rb
+++ b/spec/bundler/commands/post_bundle_message_spec.rb
@@ -3,13 +3,13 @@
RSpec.describe "post bundle message" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", "2.3.5", :group => [:emo, :test]
group :test do
gem "rspec"
end
- gem "myrack-obama", :group => :obama
+ gem "rack-obama", :group => :obama
G
end
@@ -114,26 +114,26 @@ RSpec.describe "post bundle message" do
end
it "should report a helpful error message" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "not-a-gem", :group => :development
G
expect(err).to include <<-EOS.strip
-Could not find gem 'not-a-gem' in rubygems repository https://gem.repo1/ or installed locally.
+Could not find gem 'not-a-gem' in rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally.
EOS
end
it "should report a helpful error message with reference to cache if available" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "not-a-gem", :group => :development
G
expect(err).to include("Could not find gem 'not-a-gem' in").
@@ -142,7 +142,7 @@ Could not find gem 'not-a-gem' in rubygems repository https://gem.repo1/ or inst
end
end
- describe "for second bundle install run", bundler: "< 3" do
+ describe "for second bundle install run", :bundler => "< 3" do
it "without any options" do
2.times { bundle :install }
expect(out).to include(bundle_show_message)
@@ -179,25 +179,25 @@ Could not find gem 'not-a-gem' in rubygems repository https://gem.repo1/ or inst
describe "for bundle update" do
it "shows proper messages according to the configured groups" do
- bundle :update, all: true
+ bundle :update, :all => true
expect(out).not_to include("Gems in the groups")
expect(out).to include(bundle_updated_message)
bundle "config set --local without emo"
bundle :install
- bundle :update, all: true
+ bundle :update, :all => true
expect(out).to include("Gems in the group 'emo' were not updated")
expect(out).to include(bundle_updated_message)
bundle "config set --local without emo test"
bundle :install
- bundle :update, all: true
+ bundle :update, :all => true
expect(out).to include("Gems in the groups 'emo' and 'test' were not updated")
expect(out).to include(bundle_updated_message)
bundle "config set --local without emo obama test"
bundle :install
- bundle :update, all: true
+ bundle :update, :all => true
expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not updated")
expect(out).to include(bundle_updated_message)
end
diff --git a/spec/bundler/commands/pristine_spec.rb b/spec/bundler/commands/pristine_spec.rb
index 547aa12b6c..9e496dc91a 100644
--- a/spec/bundler/commands/pristine_spec.rb
+++ b/spec/bundler/commands/pristine_spec.rb
@@ -4,7 +4,7 @@ require "bundler/vendored_fileutils"
RSpec.describe "bundle pristine" do
before :each do
- build_lib "baz", path: bundled_app do |s|
+ build_lib "baz", :path => bundled_app do |s|
s.version = "1.0.0"
s.add_development_dependency "baz-dev", "=1.0.0"
end
@@ -13,13 +13,13 @@ RSpec.describe "bundle pristine" do
build_gem "weakling"
build_gem "baz-dev", "1.0.0"
build_gem "very_simple_binary", &:add_c_extension
- build_git "foo", path: lib_path("foo")
- build_git "git_with_ext", path: lib_path("git_with_ext"), &:add_c_extension
- build_lib "bar", path: lib_path("bar")
+ build_git "foo", :path => lib_path("foo")
+ build_git "git_with_ext", :path => lib_path("git_with_ext"), &:add_c_extension
+ build_lib "bar", :path => lib_path("bar")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling"
gem "very_simple_binary"
gem "foo", :git => "#{lib_path("foo")}", :branch => "main"
@@ -164,7 +164,7 @@ RSpec.describe "bundle pristine" do
end
it "raises when one of them is not in the lockfile" do
- bundle "pristine abcabcabc", raise_on_error: false
+ bundle "pristine abcabcabc", :raise_on_error => false
expect(err).to include("Could not find gem 'abcabcabc'.")
end
end
@@ -181,8 +181,8 @@ RSpec.describe "bundle pristine" do
bundle "pristine"
makefile_contents = File.read(c_ext_dir.join("Makefile").to_s)
- expect(makefile_contents).to match(/libpath =.*#{Regexp.escape(c_ext_dir.to_s)}/)
- expect(makefile_contents).to match(/LIBPATH =.*-L#{Regexp.escape(c_ext_dir.to_s)}/)
+ expect(makefile_contents).to match(/libpath =.*#{c_ext_dir}/)
+ expect(makefile_contents).to match(/LIBPATH =.*-L#{c_ext_dir}/)
end
end
@@ -198,14 +198,14 @@ RSpec.describe "bundle pristine" do
bundle "pristine"
makefile_contents = File.read(c_ext_dir.join("Makefile").to_s)
- expect(makefile_contents).to match(/libpath =.*#{Regexp.escape(c_ext_dir.to_s)}/)
- expect(makefile_contents).to match(/LIBPATH =.*-L#{Regexp.escape(c_ext_dir.to_s)}/)
+ expect(makefile_contents).to match(/libpath =.*#{c_ext_dir}/)
+ expect(makefile_contents).to match(/LIBPATH =.*-L#{c_ext_dir}/)
end
end
context "when BUNDLE_GEMFILE doesn't exist" do
before do
- bundle "pristine", env: { "BUNDLE_GEMFILE" => "does/not/exist" }, raise_on_error: false
+ bundle "pristine", :env => { "BUNDLE_GEMFILE" => "does/not/exist" }, :raise_on_error => false
end
it "shows a meaningful error" do
diff --git a/spec/bundler/commands/remove_spec.rb b/spec/bundler/commands/remove_spec.rb
index 7ac2ea9b26..d757e0be4b 100644
--- a/spec/bundler/commands/remove_spec.rb
+++ b/spec/bundler/commands/remove_spec.rb
@@ -4,10 +4,10 @@ RSpec.describe "bundle remove" do
context "when no gems are specified" do
it "throws error" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- bundle "remove", raise_on_error: false
+ bundle "remove", :raise_on_error => false
expect(err).to include("Please specify gems to remove.")
end
@@ -16,45 +16,45 @@ RSpec.describe "bundle remove" do
context "after 'bundle install' is run" do
describe "running 'bundle remove GEM_NAME'" do
it "removes it from the lockfile" do
- myrack_dep = <<~L
+ rack_dep = <<~L
DEPENDENCIES
- myrack
+ rack
L
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle "install"
- expect(lockfile).to include(myrack_dep)
+ expect(lockfile).to include(rack_dep)
- bundle "remove myrack"
+ bundle "remove rack"
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- expect(lockfile).to_not include(myrack_dep)
+ expect(lockfile).to_not include(rack_dep)
end
end
end
- context "when --install flag is specified", bundler: "< 3" do
+ context "when --install flag is specified", :bundler => "< 3" do
it "removes gems from .bundle" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack --install"
+ bundle "remove rack --install"
- expect(out).to include("myrack was removed.")
- expect(the_bundle).to_not include_gems "myrack"
+ expect(out).to include("rack was removed.")
+ expect(the_bundle).to_not include_gems "rack"
end
end
@@ -62,39 +62,39 @@ RSpec.describe "bundle remove" do
context "when gem is present in gemfile" do
it "shows success for removed gem" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
- expect(the_bundle).to_not include_gems "myrack"
+ expect(out).to include("rack was removed.")
+ expect(the_bundle).to_not include_gems "rack"
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
context "when gem is specified in multiple lines" do
it "shows success for removed gem" do
- build_git "myrack"
+ build_git "rack"
gemfile <<-G
- source 'https://gem.repo1'
+ source '#{file_uri_for(gem_repo1)}'
gem 'git'
- gem 'myrack',
- git: "#{lib_path("myrack-1.0")}",
+ gem 'rack',
+ git: "#{lib_path("rack-1.0")}",
branch: 'main'
gem 'nokogiri'
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source 'https://gem.repo1'
+ source '#{file_uri_for(gem_repo1)}'
gem 'git'
gem 'nokogiri'
@@ -106,12 +106,12 @@ RSpec.describe "bundle remove" do
context "when gem is not present in gemfile" do
it "shows warning for gem that could not be removed" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
- expect(err).to include("`myrack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
+ expect(err).to include("`rack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
end
end
end
@@ -120,18 +120,18 @@ RSpec.describe "bundle remove" do
context "when all gems are present in gemfile" do
it "shows success fir all removed gems" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rails"
G
- bundle "remove myrack rails"
+ bundle "remove rack rails"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(out).to include("rails was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -139,18 +139,18 @@ RSpec.describe "bundle remove" do
context "when some gems are not present in the gemfile" do
it "shows warning for those not present and success for those that can be removed" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
gem "minitest"
gem "rspec"
G
- bundle "remove rails myrack minitest", raise_on_error: false
+ bundle "remove rails rack minitest", :raise_on_error => false
- expect(err).to include("`myrack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
+ expect(err).to include("`rack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
gem "minitest"
@@ -163,16 +163,16 @@ RSpec.describe "bundle remove" do
context "with inline groups" do
it "removes the specified gem" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", :group => [:dev]
+ gem "rack", :group => [:dev]
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -181,7 +181,7 @@ RSpec.describe "bundle remove" do
context "when single group block with gem to be removed is present" do
it "removes the group block" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
gem "rspec"
@@ -192,7 +192,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -200,19 +200,19 @@ RSpec.describe "bundle remove" do
context "when gem to be removed is outside block" do
it "does not modify group" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
group :test do
gem "coffee-script-source"
end
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
gem "coffee-script-source"
@@ -224,7 +224,7 @@ RSpec.describe "bundle remove" do
context "when an empty block is also present" do
it "removes all empty blocks" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
gem "rspec"
@@ -238,7 +238,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -246,7 +246,7 @@ RSpec.describe "bundle remove" do
context "when the gem belongs to multiple groups" do
it "removes the groups" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test, :serioustest do
gem "rspec"
@@ -257,7 +257,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -265,7 +265,7 @@ RSpec.describe "bundle remove" do
context "when the gem is present in multiple groups" do
it "removes all empty blocks" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :one do
gem "rspec"
@@ -280,7 +280,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -290,7 +290,7 @@ RSpec.describe "bundle remove" do
context "when all the groups will be empty after removal" do
it "removes the empty nested blocks" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
group :serioustest do
@@ -303,7 +303,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -311,10 +311,10 @@ RSpec.describe "bundle remove" do
context "when outer group will not be empty after removal" do
it "removes only empty blocks" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
- gem "myrack-test"
+ gem "rack-test"
group :serioustest do
gem "rspec"
@@ -326,10 +326,10 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
- gem "myrack-test"
+ gem "rack-test"
end
G
@@ -339,12 +339,12 @@ RSpec.describe "bundle remove" do
context "when inner group will not be empty after removal" do
it "removes only empty blocks" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
group :serioustest do
gem "rspec"
- gem "myrack-test"
+ gem "rack-test"
end
end
G
@@ -353,11 +353,11 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
group :serioustest do
- gem "myrack-test"
+ gem "rack-test"
end
end
G
@@ -369,38 +369,38 @@ RSpec.describe "bundle remove" do
context "when multiple gems are present in same line" do
it "shows warning for gems not removed" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"; gem "rails"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"; gem "rails"
G
- bundle "remove rails", raise_on_error: false
+ bundle "remove rails", :raise_on_error => false
- expect(err).to include("Gems could not be removed. myrack (>= 0) would also have been removed.")
+ expect(err).to include("Gems could not be removed. rack (>= 0) would also have been removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
- gem "myrack"; gem "rails"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"; gem "rails"
G
end
end
context "when some gems could not be removed" do
it "shows warning for gems not removed and success for those removed" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem"myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem"rack"
gem"rspec"
gem "rails"
gem "minitest"
G
- bundle "remove rails myrack rspec minitest"
+ bundle "remove rails rack rspec minitest"
expect(out).to include("rails was removed.")
expect(out).to include("minitest was removed.")
- expect(out).to include("myrack, rspec could not be removed.")
+ expect(out).to include("rack, rspec could not be removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
- gem"myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem"rack"
gem"rspec"
G
end
@@ -409,18 +409,18 @@ RSpec.describe "bundle remove" do
context "with sources" do
before do
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "rspec"
end
end
it "removes gems and empty source blocks" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
- source "https://gem.repo3" do
+ source "#{file_uri_for(gem_repo3)}" do
gem "rspec"
end
G
@@ -431,9 +431,9 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
end
end
@@ -441,40 +441,40 @@ RSpec.describe "bundle remove" do
describe "with eval_gemfile" do
context "when gems are present in both gemfiles" do
it "removes the gems" do
- gemfile "Gemfile-other", <<-G
- gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
end
end
context "when gems are present in other gemfile" do
it "removes the gems" do
- gemfile "Gemfile-other", <<-G
- gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(bundled_app("Gemfile-other").read).to_not include("gem \"myrack\"")
- expect(out).to include("myrack was removed.")
+ expect(bundled_app("Gemfile-other").read).to_not include("gem \"rack\"")
+ expect(out).to include("rack was removed.")
end
end
@@ -486,36 +486,36 @@ RSpec.describe "bundle remove" do
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
- expect(err).to include("`myrack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
+ expect(err).to include("`rack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
end
end
context "when the gem is present in parent file but not in gemfile specified by eval_gemfile" do
it "removes the gem" do
- gemfile "Gemfile-other", <<-G
+ create_file "Gemfile-other", <<-G
gem "rails"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
- expect(out).to include("myrack was removed.")
- expect(err).to include("`myrack` is not specified in #{bundled_app("Gemfile-other")} so it could not be removed.")
+ expect(out).to include("rack was removed.")
+ expect(err).to include("`rack` is not specified in #{bundled_app("Gemfile-other")} so it could not be removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
G
@@ -524,23 +524,23 @@ RSpec.describe "bundle remove" do
context "when gems cannot be removed from other gemfile" do
it "shows error" do
- gemfile "Gemfile-other", <<-G
- gem "rails"; gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rails"; gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(err).to include("Gems could not be removed. rails (>= 0) would also have been removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
G
@@ -549,47 +549,47 @@ RSpec.describe "bundle remove" do
context "when gems could not be removed from parent gemfile" do
it "shows error" do
- gemfile "Gemfile-other", <<-G
- gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "rails"; gem "myrack"
+ gem "rails"; gem "rack"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
expect(err).to include("Gems could not be removed. rails (>= 0) would also have been removed.")
- expect(bundled_app("Gemfile-other").read).to include("gem \"myrack\"")
+ expect(bundled_app("Gemfile-other").read).to include("gem \"rack\"")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "rails"; gem "myrack"
+ gem "rails"; gem "rack"
G
end
end
context "when gem present in gemfiles but could not be removed from one from one of them" do
it "removes gem which can be removed and shows warning for file from which it cannot be removed" do
- gemfile "Gemfile-other", <<-G
- gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem"myrack"
+ gem"rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
- expect(bundled_app("Gemfile-other").read).to_not include("gem \"myrack\"")
+ expect(out).to include("rack was removed.")
+ expect(bundled_app("Gemfile-other").read).to_not include("gem \"rack\"")
end
end
end
@@ -597,18 +597,18 @@ RSpec.describe "bundle remove" do
context "with install_if" do
it "removes gems inside blocks and empty blocks" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
install_if(lambda { false }) do
- gem "myrack"
+ gem "rack"
end
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -616,32 +616,32 @@ RSpec.describe "bundle remove" do
context "with env" do
it "removes gems inside blocks and empty blocks" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env "BUNDLER_TEST" do
- gem "myrack"
+ gem "rack"
end
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
context "with gemspec" do
it "should not remove the gem" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("foo.gemspec", "")
- s.add_dependency "myrack"
+ s.add_dependency "rack"
end
install_gemfile(<<-G)
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
bundle "remove foo"
@@ -654,19 +654,19 @@ RSpec.describe "bundle remove" do
context "when comment is a separate line comment" do
it "does not remove the line comment" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- # gem "myrack" might be used in the future
- gem "myrack"
+ # gem "rack" might be used in the future
+ gem "rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- # gem "myrack" might be used in the future
+ # gem "rack" might be used in the future
G
end
end
@@ -674,16 +674,16 @@ RSpec.describe "bundle remove" do
context "when gem specified for removal has an inline comment" do
it "removes the inline comment" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack" # this can be removed
+ gem "rack" # this can be removed
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -691,19 +691,19 @@ RSpec.describe "bundle remove" do
context "when gem specified for removal is mentioned in other gem's comment" do
it "does not remove other gem" do
gemfile <<-G
- source "https://gem.repo1"
- gem "puma" # implements interface provided by gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "puma" # implements interface provided by gem "rack"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
expect(out).to_not include("puma was removed.")
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
- gem "puma" # implements interface provided by gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "puma" # implements interface provided by gem "rack"
G
end
end
@@ -711,20 +711,20 @@ RSpec.describe "bundle remove" do
context "when gem specified for removal has a comment that mentions other gem" do
it "does not remove other gem" do
gemfile <<-G
- source "https://gem.repo1"
- gem "puma" # implements interface provided by gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "puma" # implements interface provided by gem "rack"
- gem "myrack"
+ gem "rack"
G
bundle "remove puma"
expect(out).to include("puma was removed.")
- expect(out).to_not include("myrack was removed.")
+ expect(out).to_not include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
end
end
diff --git a/spec/bundler/commands/show_spec.rb b/spec/bundler/commands/show_spec.rb
index 7f32d0563b..925e40b71b 100644
--- a/spec/bundler/commands/show_spec.rb
+++ b/spec/bundler/commands/show_spec.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
-RSpec.describe "bundle show", bundler: "< 3" do
+RSpec.describe "bundle show", :bundler => "< 3" do
context "with a standard Gemfile" do
before :each do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
end
@@ -50,14 +50,14 @@ RSpec.describe "bundle show", bundler: "< 3" do
end
it "complains if gem not in bundle" do
- bundle "show missing", raise_on_error: false
+ bundle "show missing", :raise_on_error => false
expect(err).to match(/could not find gem 'missing'/i)
end
it "prints path of all gems in bundle sorted by name" do
bundle "show --paths"
- expect(out).to include(default_bundle_path("gems", "rake-#{rake_version}").to_s)
+ expect(out).to include(default_bundle_path("gems", "rake-13.0.1").to_s)
expect(out).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
# Gem names are the last component of their path.
@@ -104,7 +104,7 @@ RSpec.describe "bundle show", bundler: "< 3" do
end
it "prints out branch names other than main" do
- update_git "foo", branch: "omg" do |s|
+ update_git "foo", :branch => "omg" do |s|
s.write "lib/foo.rb", "FOO = '1.0.omg'"
end
@revision = revision_for(lib_path("foo-1.0"))[0...6]
@@ -129,7 +129,7 @@ RSpec.describe "bundle show", bundler: "< 3" do
end
it "handles when a version is a '-' prerelease" do
- @git = build_git("foo", "1.0.0-beta.1", path: lib_path("foo"))
+ @git = build_git("foo", "1.0.0-beta.1", :path => lib_path("foo"))
install_gemfile <<-G
gem "foo", "1.0.0-beta.1", :git => "#{lib_path("foo")}"
G
@@ -142,20 +142,20 @@ RSpec.describe "bundle show", bundler: "< 3" do
context "in a fresh gem in a blank git repo" do
before :each do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
File.open(lib_path("foo/Gemfile"), "w") {|f| f.puts "gemspec" }
- sys_exec "rm -rf .git && git init", dir: lib_path("foo")
+ sys_exec "rm -rf .git && git init", :dir => lib_path("foo")
end
it "does not output git errors" do
- bundle :show, dir: lib_path("foo")
+ bundle :show, :dir => lib_path("foo")
expect(err_without_deprecations).to be_empty
end
end
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
@@ -167,26 +167,26 @@ RSpec.describe "bundle show", bundler: "< 3" do
context "with a valid regexp for gem name" do
it "presents alternatives", :readline do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
bundle "show rac"
- expect(out).to match(/\A1 : myrack\n2 : myrack-obama\n0 : - exit -(\n>|\z)/)
+ expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>)?\z/)
end
end
context "with an invalid regexp for gem name" do
it "does not find the gem" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
invalid_regexp = "[]"
- bundle "show #{invalid_regexp}", raise_on_error: false
+ bundle "show #{invalid_regexp}", :raise_on_error => false
expect(err).to include("Could not find gem '#{invalid_regexp}'.")
end
end
@@ -199,7 +199,7 @@ RSpec.describe "bundle show", bundler: "< 3" do
it "doesn't update gems to newer versions" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
G
@@ -219,6 +219,6 @@ RSpec.describe "bundle show", bundler: "< 3" do
end
end
-RSpec.describe "bundle show", bundler: "3" do
+RSpec.describe "bundle show", :bundler => "3" do
pending "shows a friendly error about the command removal"
end
diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb
index 1683827636..8c7b9c13c8 100644
--- a/spec/bundler/commands/update_spec.rb
+++ b/spec/bundler/commands/update_spec.rb
@@ -6,17 +6,17 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "updates the entire bundle" do
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
@@ -24,17 +24,17 @@ RSpec.describe "bundle update" do
bundle "update"
expect(out).to include("Bundle updated!")
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 3.0"
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
it "doesn't delete the Gemfile.lock file if something goes wrong" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
exit!
G
- bundle "update", raise_on_error: false
+ bundle "update", :raise_on_error => false
expect(bundled_app_lock).to exist
end
end
@@ -44,37 +44,37 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "updates the entire bundle" do
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
- bundle "update", all: true
+ bundle "update", :all => true
expect(out).to include("Bundle updated!")
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 3.0"
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
it "doesn't delete the Gemfile.lock file if something goes wrong" do
- install_gemfile "source 'https://gem.repo1'"
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
exit!
G
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
expect(bundled_app_lock).to exist
end
end
@@ -82,11 +82,11 @@ RSpec.describe "bundle update" do
describe "with --gemfile" do
it "creates lock files based on the Gemfile name" do
gemfile bundled_app("OmgFile"), <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0"
G
- bundle "update --gemfile OmgFile", all: true
+ bundle "update --gemfile OmgFile", :all => true
expect(bundled_app("OmgFile.lock")).to exist
end
@@ -96,19 +96,19 @@ RSpec.describe "bundle update" do
before { bundle "config set update_requires_all_flag true" }
it "errors when passed nothing" do
- install_gemfile "source 'https://gem.repo1'"
- bundle :update, raise_on_error: false
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ bundle :update, :raise_on_error => false
expect(err).to eq("To update everything, pass the `--all` flag.")
end
it "errors when passed --all and another option" do
- install_gemfile "source 'https://gem.repo1'"
- bundle "update --all foo", raise_on_error: false
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ bundle "update --all foo", :raise_on_error => false
expect(err).to eq("Cannot specify --all along with specific options.")
end
it "updates everything when passed --all" do
- install_gemfile "source 'https://gem.repo1'"
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
bundle "update --all"
expect(out).to include("Bundle updated!")
end
@@ -119,9 +119,9 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
@@ -137,24 +137,24 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "unlocks all child dependencies that are unrelated to other locked dependencies" do
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
- bundle "update myrack-obama"
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 2.3.5"
+ bundle "update rack-obama"
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 2.3.5"
end
end
@@ -163,19 +163,19 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "should inform the user" do
- bundle "update halting-problem-solver", raise_on_error: false
+ bundle "update halting-problem-solver", :raise_on_error => false
expect(err).to include "Could not find gem 'halting-problem-solver'"
end
it "should suggest alternatives" do
- bundle "update platformspecific", raise_on_error: false
+ bundle "update platformspecific", :raise_on_error => false
expect(err).to include "Did you mean platform_specific?"
end
end
@@ -185,22 +185,22 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "should update the child dependency" do
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
- bundle "update myrack"
- expect(the_bundle).to include_gems "myrack 1.2"
+ bundle "update rack"
+ expect(the_bundle).to include_gems "rack 1.2"
end
end
@@ -223,7 +223,7 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "slim-rails"
gem "slim_lint"
G
@@ -236,7 +236,7 @@ RSpec.describe "bundle update" do
end
end
- bundle "update", all: true
+ bundle "update", :all => true
expect(the_bundle).to include_gems("slim 3.0.9", "slim-rails 3.1.3", "slim_lint 0.16.1")
end
@@ -269,39 +269,34 @@ RSpec.describe "bundle update" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "country_select"
gem "countries"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "countries", "3.1.0")
- c.checksum(gem_repo4, "country_select", "5.1.0")
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
countries (3.1.0)
country_select (5.1.0)
countries (~> 3.0)
PLATFORMS
- #{local_platform}
+ #{specific_local_platform}
DEPENDENCIES
countries
country_select
- #{checksums}
+
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
@@ -331,7 +326,7 @@ RSpec.describe "bundle update" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "oauth2"
gem "quickbooks-ruby"
@@ -339,7 +334,7 @@ RSpec.describe "bundle update" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
faraday (2.5.2)
multi_json (1.15.0)
@@ -390,7 +385,7 @@ RSpec.describe "bundle update" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gemspec
@@ -404,7 +399,7 @@ RSpec.describe "bundle update" do
specs:
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
rake (13.0.6)
sneakers (2.11.0)
@@ -439,8 +434,8 @@ RSpec.describe "bundle update" do
build_gem "c", "2.0"
end
- install_gemfile <<-G, verbose: true
- source "https://gem.repo4"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
G
@@ -452,7 +447,7 @@ RSpec.describe "bundle update" do
end
end
- bundle "update", all: true, verbose: true
+ bundle "update", :all => true, :verbose => true
expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0")
end
@@ -464,7 +459,7 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
gem "b"
G
@@ -472,7 +467,7 @@ RSpec.describe "bundle update" do
expect(the_bundle).to include_gems("a 1.0", "b 2.0")
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
gem "b", "1.0"
G
@@ -497,27 +492,22 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "activesupport", "~> 6.1.0"
G
expect(the_bundle).to include_gems("activesupport 6.1.4.1", "tzinfo 2.0.4")
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "activesupport", "~> 6.0.0"
G
original_lockfile = lockfile
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "activesupport", "6.0.4.1"
- c.checksum gem_repo4, "tzinfo", "1.2.9"
- end
-
expected_lockfile = <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
activesupport (6.0.4.1)
tzinfo (~> 1.1)
@@ -528,7 +518,7 @@ RSpec.describe "bundle update" do
DEPENDENCIES
activesupport (~> 6.0.0)
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -553,45 +543,19 @@ RSpec.describe "bundle update" do
before do
build_repo2
- gemfile <<-G
- source "https://gem.repo2"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "doesn't hit repo2" do
- simulate_platform "x86-darwin-100" do
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- activesupport (2.3.5)
- platform_specific (1.0-x86-darwin-100)
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- activesupport
- platform_specific
- myrack-obama
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "install"
-
- FileUtils.rm_rf(gem_repo2)
-
- bundle "update --local --all"
- expect(out).not_to include("Fetching source index")
- end
+ FileUtils.rm_rf(gem_repo2)
+
+ bundle "update --local --all"
+ expect(out).not_to include("Fetching source index")
end
end
@@ -602,26 +566,26 @@ RSpec.describe "bundle update" do
it "should update only specified group gems" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", :group => :development
- gem "myrack"
+ gem "rack"
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
bundle "update --group development"
expect(the_bundle).to include_gems "activesupport 3.0"
- expect(the_bundle).not_to include_gems "myrack 1.2"
+ expect(the_bundle).not_to include_gems "rack 1.2"
end
context "when conservatively updating a group with non-group sub-deps" do
it "should update only specified group gems" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activemerchant", :group => :development
gem "activesupport"
G
@@ -637,9 +601,9 @@ RSpec.describe "bundle update" do
context "when there is a source with the same name as a gem in a group" do
before do
- build_git "foo", path: lib_path("activesupport")
+ build_git "foo", :path => lib_path("activesupport")
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", :group => :development
gem "foo", :git => "#{lib_path("activesupport")}"
G
@@ -647,7 +611,7 @@ RSpec.describe "bundle update" do
it "should not update the gems from that source" do
update_repo2 { build_gem "activesupport", "3.0" }
- update_git "foo", "2.0", path: lib_path("activesupport")
+ update_git "foo", "2.0", :path => lib_path("activesupport")
bundle "update --group development"
expect(the_bundle).to include_gems "activesupport 3.0"
@@ -658,13 +622,13 @@ RSpec.describe "bundle update" do
context "when bundler itself is a transitive dependency" do
it "executes without error" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", :group => :development
- gem "myrack"
+ gem "rack"
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
@@ -672,7 +636,7 @@ RSpec.describe "bundle update" do
bundle "update --group development"
expect(the_bundle).to include_gems "activesupport 2.3.5"
expect(the_bundle).to include_gems "bundler #{Bundler::VERSION}"
- expect(the_bundle).not_to include_gems "myrack 1.2"
+ expect(the_bundle).not_to include_gems "rack 1.2"
end
end
end
@@ -682,39 +646,39 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
- it "should fail loudly", bundler: "< 3" do
+ it "should fail loudly", :bundler => "< 3" do
bundle "install --deployment"
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
expect(last_command).to be_failure
- expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/)
- expect(err).to match(/freeze by running `bundle config set frozen false`./)
+ expect(err).to match(/You are trying to install in deployment mode after changing.your Gemfile/m)
+ expect(err).to match(/freeze \nby running `bundle config unset deployment`./m)
end
- it "should fail loudly when frozen is set globally" do
+ it "should suggest different command when frozen is set globally", :bundler => "< 3" do
bundle "config set --global frozen 1"
- bundle "update", all: true, raise_on_error: false
- expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/).
- and match(/freeze by running `bundle config set frozen false`./)
+ bundle "update", :all => true, :raise_on_error => false
+ expect(err).to match(/You are trying to install in deployment mode after changing.your Gemfile/m).
+ and match(/freeze \nby running `bundle config unset frozen`./m)
end
- it "should fail loudly when deployment is set globally" do
+ it "should suggest different command when frozen is set globally", :bundler => "3" do
bundle "config set --global deployment true"
- bundle "update", all: true, raise_on_error: false
- expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/).
- and match(/freeze by running `bundle config set frozen false`./)
+ bundle "update", :all => true, :raise_on_error => false
+ expect(err).to match(/You are trying to install in deployment mode after changing.your Gemfile/m).
+ and match(/freeze \nby running `bundle config unset deployment`./m)
end
it "should not suggest any command to unfreeze bundler if frozen is set through ENV" do
- bundle "update", all: true, raise_on_error: false, env: { "BUNDLE_FROZEN" => "true" }
- expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/)
+ bundle "update", :all => true, :raise_on_error => false, :env => { "BUNDLE_FROZEN" => "true" }
+ expect(err).to match(/You are trying to install in deployment mode after changing.your Gemfile/m)
expect(err).not_to match(/by running/)
end
end
@@ -726,7 +690,7 @@ RSpec.describe "bundle update" do
it "should not update gems not included in the source that happen to have the same name" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
update_repo2 { build_gem "activesupport", "3.0" }
@@ -737,7 +701,7 @@ RSpec.describe "bundle update" do
it "should not update gems not included in the source that happen to have the same name" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
update_repo2 { build_gem "activesupport", "3.0" }
@@ -757,7 +721,7 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "harry"
gem "fred"
G
@@ -789,7 +753,7 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "harry"
gem "fred"
G
@@ -808,144 +772,65 @@ RSpec.describe "bundle update" do
end
end
- it "shows the previous version of the gem when updated from rubygems source" do
+ it "shows the previous version of the gem when updated from rubygems source", :bundler => "< 3" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
- bundle "update", all: true, verbose: true
+ bundle "update", :all => true
expect(out).to include("Using activesupport 2.3.5")
update_repo2 do
build_gem "activesupport", "3.0"
end
- bundle "update", all: true
+ bundle "update", :all => true
expect(out).to include("Installing activesupport 3.0 (was 2.3.5)")
end
- it "only prints `Using` for versions that have changed" do
- build_repo4 do
- build_gem "bar"
- build_gem "foo"
- end
+ context "with suppress_install_using_messages set" do
+ before { bundle "config set suppress_install_using_messages true" }
- install_gemfile <<-G
- source "https://gem.repo4"
- gem "bar"
- gem "foo"
- G
+ it "only prints `Using` for versions that have changed" do
+ build_repo4 do
+ build_gem "bar"
+ build_gem "foo"
+ end
- bundle "update", all: true
- expect(out).to match(/Resolving dependencies\.\.\.\.*\nBundle updated!/)
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
+ gem "bar"
+ gem "foo"
+ G
- update_repo4 do
- build_gem "foo", "2.0"
- end
+ bundle "update", :all => true
+ expect(out).to match(/Resolving dependencies\.\.\.\.*\nBundle updated!/)
+
+ update_repo4 do
+ build_gem "foo", "2.0"
+ end
- bundle "update", all: true
- expect(out.sub("Removing foo (1.0)\n", "")).to match(/Resolving dependencies\.\.\.\.*\nFetching foo 2\.0 \(was 1\.0\)\nInstalling foo 2\.0 \(was 1\.0\)\nBundle updated/)
+ bundle "update", :all => true
+ out.sub!("Removing foo (1.0)\n", "")
+ expect(out).to match(/Resolving dependencies\.\.\.\.*\nFetching foo 2\.0 \(was 1\.0\)\nInstalling foo 2\.0 \(was 1\.0\)\nBundle updated/)
+ end
end
it "shows error message when Gemfile.lock is not preset and gem is specified" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
- bundle "update nonexisting", raise_on_error: false
+ bundle "update nonexisting", :raise_on_error => false
expect(err).to include("This Bundle hasn't been installed yet. Run `bundle install` to update and install the bundled gems.")
expect(exitstatus).to eq(22)
end
- context "with multiple sources and caching enabled" do
- before do
- build_repo2 do
- build_gem "myrack", "1.0.0"
-
- build_gem "request_store", "1.0.0" do |s|
- s.add_dependency "myrack", "1.0.0"
- end
- end
-
- build_repo4 do
- # set up repo with no gems
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- gem "request_store"
-
- source "https://gem.repo4" do
- end
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
- request_store (1.0.0)
- myrack (= 1.0.0)
-
- GEM
- remote: https://gem.repo4/
- specs:
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- request_store
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "works" do
- bundle :install
- bundle :cache
-
- update_repo2 do
- build_gem "request_store", "1.1.0" do |s|
- s.add_dependency "myrack", "1.0.0"
- end
- end
-
- bundle "update request_store"
-
- expect(out).to include("Bundle updated!")
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
- request_store (1.1.0)
- myrack (= 1.0.0)
-
- GEM
- remote: https://gem.repo4/
- specs:
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- request_store
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- context "with multiple, duplicated sources, with lockfile in old format", bundler: "< 3" do
+ context "with multiple, duplicated sources, with lockfile in old format", :bundler => "< 3" do
before do
build_repo2 do
build_gem "dotenv", "2.7.6"
@@ -956,7 +841,7 @@ RSpec.describe "bundle update" do
build_gem "vcr", "6.0.0"
end
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s|
s.add_dependency "oj"
end
@@ -986,7 +871,7 @@ RSpec.describe "bundle update" do
vcr (6.0.0)
PLATFORMS
- #{local_platform}
+ #{specific_local_platform}
DEPENDENCIES
dotenv
@@ -999,8 +884,8 @@ RSpec.describe "bundle update" do
end
it "works" do
- bundle :install, artifice: "compact_index"
- bundle "update oj", artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
+ bundle "update oj", :artifice => "compact_index"
expect(out).to include("Bundle updated!")
expect(the_bundle).to include_gems "oj 3.11.5"
@@ -1015,49 +900,49 @@ RSpec.describe "bundle update in more complicated situations" do
it "will eagerly unlock dependencies of a specified gem" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "thin"
- gem "myrack-obama"
+ gem "rack-obama"
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "thin", "2.0" do |s|
- s.add_dependency "myrack"
+ s.add_dependency "rack"
end
end
bundle "update thin"
- expect(the_bundle).to include_gems "thin 2.0", "myrack 1.2", "myrack-obama 1.0"
+ expect(the_bundle).to include_gems "thin 2.0", "rack 1.2", "rack-obama 1.0"
end
it "will warn when some explicitly updated gems are not updated" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "thin"
- gem "myrack-obama"
+ gem "rack-obama"
G
update_repo2 do
- build_gem("thin", "2.0") {|s| s.add_dependency "myrack" }
- build_gem "myrack", "10.0"
+ build_gem("thin", "2.0") {|s| s.add_dependency "rack" }
+ build_gem "rack", "10.0"
end
- bundle "update thin myrack-obama"
- expect(last_command.stdboth).to include "Bundler attempted to update myrack-obama but its version stayed the same"
- expect(the_bundle).to include_gems "thin 2.0", "myrack 10.0", "myrack-obama 1.0"
+ bundle "update thin rack-obama"
+ expect(last_command.stdboth).to include "Bundler attempted to update rack-obama but its version stayed the same"
+ expect(the_bundle).to include_gems "thin 2.0", "rack 10.0", "rack-obama 1.0"
end
it "will not warn when an explicitly updated git gem changes sha but not version" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -1071,28 +956,28 @@ RSpec.describe "bundle update in more complicated situations" do
end
it "will not warn when changing gem sources but not versions" do
- build_git "myrack"
+ build_git "rack"
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", :git => '#{lib_path("myrack-1.0")}'
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", :git => '#{lib_path("rack-1.0")}'
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "update myrack"
+ bundle "update rack"
expect(last_command.stdboth).not_to include "attempted to update"
end
it "will update only from pinned source" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- source "https://gem.repo1" do
+ source "#{file_uri_for(gem_repo1)}" do
gem "thin"
end
G
@@ -1101,12 +986,12 @@ RSpec.describe "bundle update in more complicated situations" do
build_gem "thin", "2.0"
end
- bundle "update", artifice: "compact_index"
+ bundle "update"
expect(the_bundle).to include_gems "thin 1.0"
end
context "when the lockfile is for a different platform" do
- around do |example|
+ before do
build_repo4 do
build_gem("a", "0.9")
build_gem("a", "0.9") {|s| s.platform = "java" }
@@ -1115,13 +1000,13 @@ RSpec.describe "bundle update in more complicated situations" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
G
lockfile <<-L
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
a (0.9-java)
@@ -1132,11 +1017,11 @@ RSpec.describe "bundle update in more complicated situations" do
a
L
- simulate_platform linux, &example
+ simulate_platform linux
end
it "allows updating" do
- bundle :update, all: true
+ bundle :update, :all => true
expect(the_bundle).to include_gem "a 1.1"
end
@@ -1154,13 +1039,13 @@ RSpec.describe "bundle update in more complicated situations" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "a", platform: :jruby
G
lockfile <<-L
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
a (0.9-java)
@@ -1170,14 +1055,14 @@ RSpec.describe "bundle update in more complicated situations" do
DEPENDENCIES
a
L
+
+ simulate_platform linux
end
it "is not updated because it is not actually included in the bundle" do
- simulate_platform linux do
- bundle "update a"
- expect(last_command.stdboth).to include "Bundler attempted to update a but it was not considered because it is for a different platform from the current one"
- expect(the_bundle).to_not include_gem "a"
- end
+ bundle "update a"
+ expect(last_command.stdboth).to include "Bundler attempted to update a but it was not considered because it is for a different platform from the current one"
+ expect(the_bundle).to_not include_gem "a"
end
end
end
@@ -1187,14 +1072,14 @@ RSpec.describe "bundle update without a Gemfile.lock" do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack", "1.0"
+ gem "rack", "1.0"
G
- bundle "update", all: true
+ bundle "update", :all => true
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -1202,23 +1087,23 @@ RSpec.describe "bundle update when a gem depends on a newer version of bundler"
before do
build_repo2 do
build_gem "rails", "3.0.1" do |s|
- s.add_dependency "bundler", "9.9.9"
+ s.add_dependency "bundler", Bundler::VERSION.succ
end
- build_gem "bundler", "9.9.9"
+ build_gem "bundler", Bundler::VERSION.succ
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0.1"
G
end
it "should explain that bundler conflicted and how to resolve the conflict" do
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
expect(last_command.stdboth).not_to match(/in snapshot/i)
expect(err).to match(/current Bundler version/i).
- and match(/Install the necessary version with `gem install bundler:9\.9\.9`/i)
+ and match(/Install the necessary version with `gem install bundler:#{Bundler::VERSION.succ}`/i)
end
end
@@ -1227,27 +1112,26 @@ RSpec.describe "bundle update --ruby" do
before do
install_gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
-
it "removes the Ruby from the Gemfile.lock" do
bundle "update --ruby"
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- #{checksums_section_when_enabled}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1258,33 +1142,32 @@ RSpec.describe "bundle update --ruby" do
before do
install_gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
gemfile <<-G
- ruby '~> #{current_ruby_minor}'
- source "https://gem.repo1"
+ ruby '~> #{current_ruby_minor}'
+ source "#{file_uri_for(gem_repo1)}"
G
end
-
it "updates the Gemfile.lock with the latest version" do
bundle "update --ruby"
expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo1/
- specs:
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
- PLATFORMS
- #{lockfile_platforms}
+ PLATFORMS
+ #{lockfile_platforms}
- DEPENDENCIES
- #{checksums_section_when_enabled}
- RUBY VERSION
- #{Bundler::RubyVersion.system}
+ DEPENDENCIES
- BUNDLED WITH
- #{Bundler::VERSION}
+ RUBY VERSION
+ #{Bundler::RubyVersion.system}
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
end
@@ -1293,16 +1176,16 @@ RSpec.describe "bundle update --ruby" do
before do
install_gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
gemfile <<-G
ruby '~> 2.1.0'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
it "shows a helpful error message" do
- bundle "update --ruby", raise_on_error: false
+ bundle "update --ruby", :raise_on_error => false
expect(err).to include("Your Ruby version is #{Bundler::RubyVersion.system.gem_version}, but your Gemfile specified ~> 2.1.0")
end
@@ -1312,7 +1195,7 @@ RSpec.describe "bundle update --ruby" do
before do
lockfile <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -1320,8 +1203,6 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
- CHECKSUMS
-
RUBY VERSION
ruby 2.1.4p222
@@ -1331,16 +1212,15 @@ RSpec.describe "bundle update --ruby" do
gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
-
it "updates the Gemfile.lock with the latest version" do
bundle "update --ruby"
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -1348,8 +1228,6 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
- CHECKSUMS
-
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1361,249 +1239,140 @@ RSpec.describe "bundle update --ruby" do
end
RSpec.describe "bundle update --bundler" do
- it "updates the bundler version in the lockfile" do
+ it "updates the bundler version in the lockfile without re-resolving" do
build_repo4 do
- build_gem "bundler", "2.5.9"
- build_gem "myrack", "1.0"
- end
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
+ build_gem "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- myrack (1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2')
- bundle :update, bundler: true, verbose: true
+ FileUtils.rm_r gem_repo4
+
+ bundle :update, :bundler => true, :artifice => "compact_index", :verbose => true
expect(out).to include("Using bundler #{Bundler::VERSION}")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
L
- expect(the_bundle).to include_gem "myrack 1.0"
+ expect(the_bundle).to include_gem "rack 1.0"
end
it "updates the bundler version in the lockfile without re-resolving if the highest version is already installed" do
+ system_gems "bundler-2.3.9"
+
build_repo4 do
- build_gem "bundler", "2.3.9"
- build_gem "myrack", "1.0"
+ build_gem "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
- end
-
- bundle :update, bundler: true, verbose: true
+ bundle :update, :bundler => true, :artifice => "compact_index", :verbose => true
expect(out).to include("Using bundler #{Bundler::VERSION}")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
L
- expect(the_bundle).to include_gem "myrack 1.0"
+ expect(the_bundle).to include_gem "rack 1.0"
end
- it "updates the bundler version in the lockfile even if the latest version is not installed", :ruby_repo do
- pristine_system_gems "bundler-2.99.9"
+ it "updates the bundler version in the lockfile even if the latest version is not installed", :ruby_repo, :realworld do
+ pristine_system_gems "bundler-2.3.9"
build_repo4 do
- build_gem "myrack", "1.0"
-
- build_bundler "999.0.0"
+ build_gem "rack", "1.0"
end
- install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ install_gemfile <<-G, :env => { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
- lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.99.9")
+ lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
- bundle :update, bundler: true, verbose: true, preserve_ruby_flags: true
+ bundle :update, :bundler => true, :artifice => "vcr", :verbose => true, :env => { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
# Only updates properly on modern RubyGems.
if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
- expect(out).to include("Updating bundler to 999.0.0")
- expect(out).to include("Running `bundle update --bundler \"> 0.a\" --verbose` with bundler 999.0.0")
- expect(out).not_to include("Installing Bundler 2.99.9 and restarting using that version.")
+ expect(out).to include("Updating bundler to 2.3.10")
+ expect(out).to include("Using bundler 2.3.10")
+ expect(out).not_to include("Installing Bundler 2.3.9 and restarting using that version.")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
- 999.0.0
+ 2.3.10
L
- expect(the_bundle).to include_gems "bundler 999.0.0"
- expect(the_bundle).to include_gems "myrack 1.0"
- else
- # Old RubyGems versions do not trampoline but they still change BUNDLED
- # WITH to the latest bundler version. This means the below check fails
- # because it tries to use bundler 999.0.0 which did not get installed.
- # Workaround the bug by forcing the version we know is installed.
- expect(the_bundle).to include_gems "myrack 1.0", env: { "BUNDLER_VERSION" => "2.99.9" }
- end
- end
-
- it "does not claim to update to Bundler version to a wrong version when cached gems are present" do
- pristine_system_gems "bundler-2.99.0"
-
- build_repo4 do
- build_gem "myrack", "3.0.9.1"
-
- build_bundler "2.99.0"
+ expect(the_bundle).to include_gems "bundler 2.3.10"
end
- gemfile <<~G
- source "https://gem.repo4"
- gem "myrack"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- myrack (3.0.9.1)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack
-
- BUNDLED WITH
- 2.99.0
- L
-
- bundle :cache, verbose: true
-
- bundle :update, bundler: true, verbose: true
-
- expect(out).not_to include("Updating bundler to")
- end
-
- it "does not update the bundler version in the lockfile if the latest version is not compatible with current ruby", :ruby_repo do
- pristine_system_gems "bundler-9.9.9"
-
- build_repo4 do
- build_gem "myrack", "1.0"
-
- build_bundler "9.9.9"
- build_bundler "999.0.0" do |s|
- s.required_ruby_version = "> #{Gem.ruby_version}"
- end
- end
-
- checksums = checksums_section do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
- end
-
- install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
- G
-
- bundle :update, bundler: true, verbose: true
-
- expect(out).to include("Using bundler 9.9.9")
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- myrack (1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack
- #{checksums}
- BUNDLED WITH
- 9.9.9
- L
-
- expect(the_bundle).to include_gems "bundler 9.9.9"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
- it "errors if the explicit target version does not exist" do
- pristine_system_gems "bundler-9.9.9"
+ it "errors if the explicit target version does not exist", :realworld do
+ pristine_system_gems "bundler-2.3.9"
build_repo4 do
- build_gem "myrack", "1.0"
+ build_gem "rack", "1.0"
end
- install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ install_gemfile <<-G, :env => { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
+ lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
- bundle :update, bundler: "999.999.999", raise_on_error: false
+ bundle :update, :bundler => "999.999.999", :artifice => "vcr", :raise_on_error => false
# Only gives a meaningful error message on modern RubyGems.
if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
expect(last_command).to be_failure
- expect(err).to eq("The `bundle update --bundler` target version (999.999.999) does not exist")
+ expect(err).to include("The `bundle update --bundler` target version (999.999.999) does not exist")
end
end
@@ -1611,34 +1380,31 @@ RSpec.describe "bundle update --bundler" do
system_gems "bundler-2.3.0.dev"
build_repo4 do
- build_gem "myrack", "1.0"
+ build_gem "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
- bundle :update, bundler: "2.3.0.dev", verbose: "true"
+ bundle :update, :bundler => "2.3.0.dev"
# Only updates properly on modern RubyGems.
- if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
- end
+ if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
2.3.0.dev
L
@@ -1651,36 +1417,33 @@ RSpec.describe "bundle update --bundler" do
system_gems "bundler-2.3.9"
build_repo4 do
- build_gem "myrack", "1.0"
+ build_gem "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
- bundle :update, bundler: "2.3.9", verbose: true
+ bundle :update, :bundler => "2.3.9", :raise_on_error => false
expect(out).not_to include("Fetching gem metadata from https://rubygems.org/")
# Only updates properly on modern RubyGems.
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
- end
if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
2.3.9
L
@@ -1688,31 +1451,6 @@ RSpec.describe "bundle update --bundler" do
expect(out).to include("Using bundler 2.3.9")
end
end
-
- it "prints an error when trying to update bundler in frozen mode" do
- system_gems "bundler-2.3.9"
-
- gemfile <<~G
- source "https://gem.repo2"
- G
-
- lockfile <<-L
- GEM
- remote: https://gem.repo2/
- specs:
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
-
- BUNDLED WITH
- 2.1.4
- L
-
- bundle "update --bundler=2.3.9", env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
- expect(err).to include("An update to the version of bundler itself was requested, but the lockfile can't be updated because frozen mode is set")
- end
end
# these specs are slow and focus on integration and therefore are not exhaustive. unit specs elsewhere handle that.
@@ -1738,7 +1476,7 @@ RSpec.describe "bundle update conservative" do
# establish a lockfile set to 1.4.3
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo', '1.4.3'
gem 'bar', '2.0.3'
gem 'qux', '1.0.0'
@@ -1747,7 +1485,7 @@ RSpec.describe "bundle update conservative" do
# remove 1.4.3 requirement and bar altogether
# to setup update specs below
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo'
gem 'qux'
G
@@ -1770,7 +1508,7 @@ RSpec.describe "bundle update conservative" do
end
it "update all" do
- bundle "update --patch", all: true
+ bundle "update --patch", :all => true
expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.1"
end
@@ -1792,7 +1530,7 @@ RSpec.describe "bundle update conservative" do
end
it "minor preferred" do
- bundle "update --minor --strict", all: true
+ bundle "update --minor --strict", :all => true
expect(the_bundle).to include_gems "foo 1.5.0", "bar 2.1.1", "qux 1.1.0"
end
@@ -1843,7 +1581,7 @@ RSpec.describe "bundle update conservative" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'isolated_owner'
gem 'shared_owner_a'
@@ -1852,7 +1590,7 @@ RSpec.describe "bundle update conservative" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
isolated_dep (2.0.1)
isolated_owner (1.0.1)
@@ -1864,15 +1602,13 @@ RSpec.describe "bundle update conservative" do
shared_dep (~> 5.0)
PLATFORMS
- #{local_platform}
+ #{specific_local_platform}
DEPENDENCIES
isolated_owner
shared_owner_a
shared_owner_b
- CHECKSUMS
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1905,17 +1641,9 @@ RSpec.describe "bundle update conservative" do
it "should only change direct dependencies when updating the lockfile with --conservative" do
bundle "lock --update --conservative"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "isolated_dep", "2.0.1"
- c.checksum gem_repo4, "isolated_owner", "1.0.2"
- c.checksum gem_repo4, "shared_dep", "5.0.1"
- c.checksum gem_repo4, "shared_owner_a", "3.0.2"
- c.checksum gem_repo4, "shared_owner_b", "4.0.2"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
isolated_dep (2.0.1)
isolated_owner (1.0.2)
@@ -1927,13 +1655,13 @@ RSpec.describe "bundle update conservative" do
shared_dep (~> 5.0)
PLATFORMS
- #{local_platform}
+ #{specific_local_platform}
DEPENDENCIES
isolated_owner
shared_owner_a
shared_owner_b
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1941,7 +1669,7 @@ RSpec.describe "bundle update conservative" do
it "should match bundle install conservative update behavior when not eagerly unlocking" do
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'isolated_owner', '1.0.2'
gem 'shared_owner_a', '3.0.2'
@@ -1954,59 +1682,13 @@ RSpec.describe "bundle update conservative" do
end
end
- context "when Gemfile dependencies have changed" do
- before do
- build_repo4 do
- build_gem "nokogiri", "1.16.4" do |s|
- s.platform = "arm64-darwin"
- end
-
- build_gem "nokogiri", "1.16.4" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "prism", "0.25.0"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
- gem "nokogiri", ">=1.16.4"
- gem "prism", ">=0.25.0"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.16.4-arm64-darwin)
- nokogiri (1.16.4-x86_64-linux)
-
- PLATFORMS
- arm64-darwin
- x86_64-linux
-
- DEPENDENCIES
- nokogiri (>= 1.16.4)
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "still works" do
- simulate_platform "arm64-darwin-23" do
- bundle "update"
- end
- end
- end
-
context "error handling" do
before do
- gemfile "source 'https://gem.repo1'"
+ gemfile "source \"#{file_uri_for(gem_repo1)}\""
end
it "raises if too many flags are provided" do
- bundle "update --patch --minor", all: true, raise_on_error: false
+ bundle "update --patch --minor", :all => true, :raise_on_error => false
expect(err).to eq "Provide only one of the following options: minor, patch"
end
diff --git a/spec/bundler/commands/version_spec.rb b/spec/bundler/commands/version_spec.rb
index 307058a5dd..53d545f5fa 100644
--- a/spec/bundler/commands/version_spec.rb
+++ b/spec/bundler/commands/version_spec.rb
@@ -4,42 +4,42 @@ require_relative "../support/path"
RSpec.describe "bundle version" do
if Spec::Path.ruby_core?
- COMMIT_HASH = /unknown|[a-fA-F0-9]{7,}/
+ COMMIT_HASH = /unknown|[a-fA-F0-9]{7,}/.freeze
else
- COMMIT_HASH = /[a-fA-F0-9]{7,}/
+ COMMIT_HASH = /[a-fA-F0-9]{7,}/.freeze
end
context "with -v" do
- it "outputs the version", bundler: "< 3" do
+ it "outputs the version", :bundler => "< 3" do
bundle "-v"
expect(out).to eq("Bundler version #{Bundler::VERSION}")
end
- it "outputs the version", bundler: "3" do
+ it "outputs the version", :bundler => "3" do
bundle "-v"
expect(out).to eq(Bundler::VERSION)
end
end
context "with --version" do
- it "outputs the version", bundler: "< 3" do
+ it "outputs the version", :bundler => "< 3" do
bundle "--version"
expect(out).to eq("Bundler version #{Bundler::VERSION}")
end
- it "outputs the version", bundler: "3" do
+ it "outputs the version", :bundler => "3" do
bundle "--version"
expect(out).to eq(Bundler::VERSION)
end
end
context "with version" do
- it "outputs the version with build metadata", bundler: "< 3" do
+ it "outputs the version with build metadata", :bundler => "< 3" do
bundle "version"
expect(out).to match(/\ABundler version #{Regexp.escape(Bundler::VERSION)} \(\d{4}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
end
- it "outputs the version with build metadata", bundler: "3" do
+ it "outputs the version with build metadata", :bundler => "3" do
bundle "version"
expect(out).to match(/\A#{Regexp.escape(Bundler::VERSION)} \(\d{4}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
end
diff --git a/spec/bundler/commands/viz_spec.rb b/spec/bundler/commands/viz_spec.rb
index c26e3c81ed..cf612397ab 100644
--- a/spec/bundler/commands/viz_spec.rb
+++ b/spec/bundler/commands/viz_spec.rb
@@ -1,22 +1,22 @@
# frozen_string_literal: true
-RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld: true do
+RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot"), :realworld => true do
before do
realworld_system_gems "ruby-graphviz --version 1.2.5"
end
it "graphs gems from the Gemfile" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
bundle "viz"
expect(out).to include("gem_graph.png")
- bundle "viz", format: "debug"
- expect(out).to eq(<<~DOT.strip)
+ bundle "viz", :format => "debug"
+ expect(out).to eq(strip_whitespace(<<-DOT).strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -25,11 +25,11 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
node[ fontname = "Arial, Helvetica, SansSerif"];
edge[ fontname = "Arial, Helvetica, SansSerif" , fontsize = "12"];
default [style = "filled", fillcolor = "#B9B9D5", shape = "box3d", fontsize = "16", label = "default"];
- myrack [style = "filled", fillcolor = "#B9B9D5", label = "myrack"];
- default -> myrack [constraint = "false"];
- "myrack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "myrack-obama"];
- default -> "myrack-obama" [constraint = "false"];
- "myrack-obama" -> myrack;
+ rack [style = "filled", fillcolor = "#B9B9D5", label = "rack"];
+ default -> rack [constraint = "false"];
+ "rack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "rack-obama"];
+ default -> "rack-obama" [constraint = "false"];
+ "rack-obama" -> rack;
}
debugging bundle viz...
DOT
@@ -37,20 +37,20 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
it "graphs gems that are prereleases" do
build_repo2 do
- build_gem "myrack", "1.3.pre"
+ build_gem "rack", "1.3.pre"
end
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "= 1.3.pre"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "= 1.3.pre"
+ gem "rack-obama"
G
bundle "viz"
expect(out).to include("gem_graph.png")
- bundle "viz", format: :debug, version: true
- expect(out).to eq(<<~EOS.strip)
+ bundle "viz", :format => :debug, :version => true
+ expect(out).to eq(strip_whitespace(<<-EOS).strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -59,11 +59,11 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
node[ fontname = "Arial, Helvetica, SansSerif"];
edge[ fontname = "Arial, Helvetica, SansSerif" , fontsize = "12"];
default [style = "filled", fillcolor = "#B9B9D5", shape = "box3d", fontsize = "16", label = "default"];
- myrack [style = "filled", fillcolor = "#B9B9D5", label = "myrack\\n1.3.pre"];
- default -> myrack [constraint = "false"];
- "myrack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "myrack-obama\\n1.0"];
- default -> "myrack-obama" [constraint = "false"];
- "myrack-obama" -> myrack;
+ rack [style = "filled", fillcolor = "#B9B9D5", label = "rack\\n1.3.pre"];
+ default -> rack [constraint = "false"];
+ "rack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "rack-obama\\n1.0"];
+ default -> "rack-obama" [constraint = "false"];
+ "rack-obama" -> rack;
}
debugging bundle viz...
EOS
@@ -77,18 +77,18 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
end
end
- system_gems "graphviz-999", gem_repo: gem_repo4
+ system_gems "graphviz-999", :gem_repo => gem_repo4
end
it "loads the correct ruby-graphviz gem" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
- bundle "viz", format: "debug"
- expect(out).to eq(<<~DOT.strip)
+ bundle "viz", :format => "debug"
+ expect(out).to eq(strip_whitespace(<<-DOT).strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -97,11 +97,11 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
node[ fontname = "Arial, Helvetica, SansSerif"];
edge[ fontname = "Arial, Helvetica, SansSerif" , fontsize = "12"];
default [style = "filled", fillcolor = "#B9B9D5", shape = "box3d", fontsize = "16", label = "default"];
- myrack [style = "filled", fillcolor = "#B9B9D5", label = "myrack"];
- default -> myrack [constraint = "false"];
- "myrack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "myrack-obama"];
- default -> "myrack-obama" [constraint = "false"];
- "myrack-obama" -> myrack;
+ rack [style = "filled", fillcolor = "#B9B9D5", label = "rack"];
+ default -> rack [constraint = "false"];
+ "rack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "rack-obama"];
+ default -> "rack-obama" [constraint = "false"];
+ "rack-obama" -> rack;
}
debugging bundle viz...
DOT
@@ -111,7 +111,7 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
context "--without option" do
it "one group" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
group :rails do
@@ -125,11 +125,11 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
it "two groups" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
- group :myrack do
- gem "myrack"
+ group :rack do
+ gem "rack"
end
group :rails do
@@ -137,7 +137,7 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
end
G
- bundle "viz --without=rails:myrack"
+ bundle "viz --without=rails:rack"
expect(out).to include("gem_graph.png")
end
end
diff --git a/spec/bundler/install/allow_offline_install_spec.rb b/spec/bundler/install/allow_offline_install_spec.rb
index 21b0568f7d..4c6c77a61e 100644
--- a/spec/bundler/install/allow_offline_install_spec.rb
+++ b/spec/bundler/install/allow_offline_install_spec.rb
@@ -7,17 +7,17 @@ RSpec.describe "bundle install with :allow_offline_install" do
context "with no cached data locally" do
it "still installs" do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "http://testgemserver.local"
- gem "myrack-obama"
+ gem "rack-obama"
G
- expect(the_bundle).to include_gem("myrack 1.0")
+ expect(the_bundle).to include_gem("rack 1.0")
end
it "still fails when the network is down" do
- install_gemfile <<-G, artifice: "fail", raise_on_error: false
+ install_gemfile <<-G, :artifice => "fail", :raise_on_error => false
source "http://testgemserver.local"
- gem "myrack-obama"
+ gem "rack-obama"
G
expect(err).to include("Could not reach host testgemserver.local.")
expect(the_bundle).to_not be_locked
@@ -26,37 +26,37 @@ RSpec.describe "bundle install with :allow_offline_install" do
context "with cached data locally" do
it "will install from the compact index" do
- system_gems ["myrack-1.0.0"], path: default_bundle_path
+ system_gems ["rack-1.0.0"], :path => default_bundle_path
bundle "config set clean false"
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "http://testgemserver.local"
- gem "myrack-obama"
- gem "myrack", "< 1.0"
+ gem "rack-obama"
+ gem "rack", "< 1.0"
G
- expect(the_bundle).to include_gems("myrack-obama 1.0", "myrack 0.9.1")
+ expect(the_bundle).to include_gems("rack-obama 1.0", "rack 0.9.1")
gemfile <<-G
source "http://testgemserver.local"
- gem "myrack-obama"
+ gem "rack-obama"
G
- bundle :update, artifice: "fail", all: true
+ bundle :update, :artifice => "fail", :all => true
expect(last_command.stdboth).to include "Using the cached data for the new index because of a network error"
- expect(the_bundle).to include_gems("myrack-obama 1.0", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack-obama 1.0", "rack 1.0.0")
end
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 --no-tags)
+ fetch_args = %w(fetch --force --quiet)
clone_args = %w(clone --bare --no-hardlinks --quiet)
- if (fetch_args.-(ARGV).empty? || clone_args.-(ARGV).empty?) && File.exist?(ARGV[ARGV.index("--") + 1])
+ if (fetch_args.-(ARGV).empty? || clone_args.-(ARGV).empty?) && ARGV.any? {|arg| arg.start_with?("file://") }
warn "git remote ops have been disabled"
exit 1
end
@@ -75,20 +75,20 @@ RSpec.describe "bundle install with :allow_offline_install" do
it "will install from a cached git repo" do
skip "doesn't print errors" if Gem.win_platform?
- git = build_git "a", "1.0.0", path: lib_path("a")
- update_git("a", path: git.path, branch: "new_branch")
+ git = build_git "a", "1.0.0", :path => lib_path("a")
+ update_git("a", :path => git.path, :branch => "new_branch")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "a", :git => #{git.path.to_s.dump}
G
- break_git_remote_ops! { bundle :update, all: true }
+ break_git_remote_ops! { bundle :update, :all => true }
expect(err).to include("Using cached git data because of network errors")
expect(the_bundle).to be_locked
break_git_remote_ops! do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "a", :git => #{git.path.to_s.dump}, :branch => "new_branch"
G
end
diff --git a/spec/bundler/install/binstubs_spec.rb b/spec/bundler/install/binstubs_spec.rb
index 00765ac6dd..928ba80b15 100644
--- a/spec/bundler/install/binstubs_spec.rb
+++ b/spec/bundler/install/binstubs_spec.rb
@@ -6,14 +6,14 @@ RSpec.describe "bundle install" do
expect(Pathname.new("/usr/bin")).not_to be_writable
gemfile <<-G
def Gem.bindir; "/usr/bin"; end
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
config "BUNDLE_SYSTEM_BINDIR" => system_gem_path("altbin").to_s
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
- expect(system_gem_path("altbin/myrackup")).to exist
+ expect(the_bundle).to include_gems "rack 1.0.0"
+ expect(system_gem_path("altbin/rackup")).to exist
end
end
@@ -21,26 +21,26 @@ RSpec.describe "bundle install" do
before do
build_repo2 do
build_gem "fake", "14" do |s|
- s.executables = "myrackup"
+ s.executables = "rackup"
end
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "fake"
- gem "myrack"
+ gem "rack"
G
end
it "warns about the situation" do
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(last_command.stderr).to include(
- "The `myrackup` executable in the `fake` gem is being loaded, but it's also present in other gems (myrack).\n" \
+ "The `rackup` executable in the `fake` gem is being loaded, but it's also present in other gems (rack).\n" \
"If you meant to run the executable for another gem, make sure you use a project specific binstub (`bundle binstub <gem_name>`).\n" \
"If you plan to use multiple conflicting executables, generate binstubs for them and disambiguate their names."
).or include(
- "The `myrackup` executable in the `myrack` gem is being loaded, but it's also present in other gems (fake).\n" \
+ "The `rackup` executable in the `rack` gem is being loaded, but it's also present in other gems (fake).\n" \
"If you meant to run the executable for another gem, make sure you use a project specific binstub (`bundle binstub <gem_name>`).\n" \
"If you plan to use multiple conflicting executables, generate binstubs for them and disambiguate their names."
)
diff --git a/spec/bundler/install/bundler_spec.rb b/spec/bundler/install/bundler_spec.rb
index 56f8431181..e7ec3bc7e7 100644
--- a/spec/bundler/install/bundler_spec.rb
+++ b/spec/bundler/install/bundler_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe "bundle install" do
before(:each) do
build_repo2 do
build_gem "rails", "3.0" do |s|
- s.add_dependency "bundler", ">= 0.9.0"
+ s.add_dependency "bundler", ">= 0.9.0.pre"
end
build_gem "bundler", "0.9.1"
build_gem "bundler", Bundler::VERSION
@@ -14,7 +14,7 @@ RSpec.describe "bundle install" do
it "are forced to the current bundler version" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
G
@@ -23,20 +23,20 @@ RSpec.describe "bundle install" do
it "are forced to the current bundler version even if not already present" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect(the_bundle).to include_gems "bundler #{Bundler::VERSION}"
end
it "causes a conflict if explicitly requesting a different version of bundler" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
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
@@ -50,17 +50,17 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if explicitly requesting a non matching requirement on bundler" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
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
- and the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler >= 0.9.0, < 1.A,
+ Because rails >= 3.0 depends on bundler >= 0.9.0.pre
+ and the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler >= 0.9.0.pre, < 1.A,
rails >= 3.0 requires bundler >= 1.A.
So, because Gemfile depends on rails = 3.0
and Gemfile depends on bundler ~> 0.8,
@@ -73,13 +73,13 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if explicitly requesting a version of bundler that doesn't exist" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
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
@@ -99,16 +99,16 @@ RSpec.describe "bundle install" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "multiple_versioned_deps"
G
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "multiple_versioned_deps"
- gem "myrack"
+ gem "rack"
G
expect(the_bundle).to include_gems "multiple_versioned_deps 1.0.0"
@@ -116,7 +116,7 @@ RSpec.describe "bundle install" do
it "includes bundler in the bundle when it's a child dependency" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
G
@@ -126,8 +126,8 @@ RSpec.describe "bundle install" do
it "allows gem 'bundler' when Bundler is not in the Gemfile or its dependencies" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
run "begin; gem 'bundler'; puts 'WIN'; rescue Gem::LoadError => e; puts e.backtrace; end"
@@ -143,13 +143,13 @@ RSpec.describe "bundle install" do
end
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "activemerchant"
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
@@ -171,13 +171,13 @@ RSpec.describe "bundle install" do
end
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails_pinned_to_old_activesupport"
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
@@ -197,12 +197,12 @@ RSpec.describe "bundle install" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'rails', "2.3.2"
G
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails_pinned_to_old_activesupport"
G
@@ -219,17 +219,17 @@ RSpec.describe "bundle install" do
bundle "config set path.system true"
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'rails', "7.0.4"
G
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'rails', "7.0.3"
G
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'rails', "7.0.4"
G
@@ -243,7 +243,7 @@ RSpec.describe "bundle install" do
system_gems "bundler-99999999.99.1"
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
G
@@ -257,7 +257,7 @@ RSpec.describe "bundle install" do
system_gems "bundler-99999999.99.1"
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
G
diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb
index bd39ac5cc1..3bcb6a703e 100644
--- a/spec/bundler/install/deploy_spec.rb
+++ b/spec/bundler/install/deploy_spec.rb
@@ -3,31 +3,31 @@
RSpec.describe "install in deployment or frozen mode" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
- context "with CLI flags", bundler: "< 3" 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")
+ bundle "install --deployment", :raise_on_error => false
+ 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")
+ bundle "install --frozen", :raise_on_error => false
+ expect(err).to include("The --frozen flag requires a Gemfile.lock")
end
it "disallows --deployment --system" do
- bundle "install --deployment --system", raise_on_error: false
+ bundle "install --deployment --system", :raise_on_error => false
expect(err).to include("You have specified both --deployment")
expect(err).to include("Please choose only one option")
expect(exitstatus).to eq(15)
end
it "disallows --deployment --path --system" do
- bundle "install --deployment --path . --system", raise_on_error: false
+ bundle "install --deployment --path . --system", :raise_on_error => false
expect(err).to include("You have specified both --path")
expect(err).to include("as well as --system")
expect(err).to include("Please choose only one option")
@@ -35,55 +35,10 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "doesn't mess up a subsequent `bundle install` after you try to deploy without a lock" do
- bundle "install --deployment", raise_on_error: false
+ bundle "install --deployment", :raise_on_error => false
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
-
- it "installs gems by default to vendor/bundle" do
- bundle :lock
- bundle "install --deployment"
- expect(out).to include("vendor/bundle")
- end
-
- it "installs gems to custom path if specified" do
- bundle :lock
- bundle "install --path vendor/bundle2 --deployment"
- expect(out).to include("vendor/bundle2")
- end
-
- it "works with the --frozen flag" do
- bundle :lock
- bundle "install --frozen"
- end
-
- it "explodes with the --deployment flag if you make a change and don't check in the lockfile" do
- bundle :lock
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
- G
-
- bundle "install --deployment", raise_on_error: false
- expect(err).to include("frozen mode")
- expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
- expect(err).not_to include("You have deleted from the Gemfile")
- expect(err).not_to include("You have changed in the Gemfile")
- end
- end
-
- it "fails without a lockfile and says that deployment requires a lock" do
- bundle "config deployment true"
- bundle "install", raise_on_error: false
- expect(err).to include("The deployment setting requires a lockfile")
- end
-
- it "fails without a lockfile and says that frozen requires a lock" do
- bundle "config frozen true"
- bundle "install", raise_on_error: false
- expect(err).to include("The frozen setting requires a lockfile")
end
it "still works if you are not in the app directory and specify --gemfile" do
@@ -91,14 +46,14 @@ RSpec.describe "install in deployment or frozen mode" do
simulate_new_machine
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
- bundle "install --gemfile #{tmp}/bundled_app/Gemfile", dir: tmp
- expect(the_bundle).to include_gems "myrack 1.0"
+ bundle "install --gemfile #{tmp}/bundled_app/Gemfile", :dir => tmp
+ expect(the_bundle).to include_gems "rack 1.0"
end
it "works if you exclude a group with a git gem" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
gem "foo", :git => "#{lib_path("foo-1.0")}"
end
@@ -115,14 +70,14 @@ RSpec.describe "install in deployment or frozen mode" do
bundle :install
bundle "config set --local deployment true"
bundle :install
- bundle "exec bundle check", env: { "PATH" => path }
+ bundle "exec bundle check", :env => { "PATH" => path }
end
it "works when using path gems from the same path and the version is specified" do
- build_lib "foo", path: lib_path("nested/foo")
- build_lib "bar", path: lib_path("nested/bar")
+ build_lib "foo", :path => lib_path("nested/foo")
+ build_lib "bar", :path => lib_path("nested/bar")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :path => "#{lib_path("nested")}"
gem "bar", :path => "#{lib_path("nested")}"
G
@@ -133,9 +88,9 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "works when path gems are specified twice" do
- build_lib "foo", path: lib_path("nested/foo")
+ build_lib "foo", :path => lib_path("nested/foo")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("nested/foo")}"
gem "foo", :path => "#{lib_path("nested/foo")}"
G
@@ -146,28 +101,28 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "works when there are credentials in the source URL" do
- install_gemfile(<<-G, artifice: "endpoint_strict_basic_authentication", quiet: true)
+ install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true)
source "http://user:pass@localgemserver.test/"
- gem "myrack-obama", ">= 1.0"
+ gem "rack-obama", ">= 1.0"
G
bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
end
it "works with sources given by a block" do
install_gemfile <<-G
- source "https://gem.repo1"
- source "https://gem.repo1" do
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo1)}" do
+ gem "rack"
end
G
bundle "config set --local deployment true"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
context "when replacing a host with the same host with credentials" do
@@ -176,29 +131,69 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "install"
gemfile <<-G
source "http://user_name:password@localgemserver.test/"
- gem "myrack"
+ gem "rack"
G
lockfile <<-G
GEM
remote: http://localgemserver.test/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
- #{generic_local_platform}
+ #{local}
DEPENDENCIES
- myrack
+ rack
G
bundle "config set --local deployment true"
end
- it "allows the replace" do
- bundle :install
+ it "prevents the replace by default" do
+ bundle :install, :raise_on_error => false
+
+ expect(err).to match(/The list of sources changed/)
+ end
+
+ context "when allow_deployment_source_credential_changes is true" do
+ before { bundle "config set allow_deployment_source_credential_changes true" }
+
+ it "allows the replace" do
+ bundle :install
+
+ expect(out).to match(/Bundle complete!/)
+ end
+ end
+
+ context "when allow_deployment_source_credential_changes is false" do
+ before { bundle "config set allow_deployment_source_credential_changes false" }
+
+ it "prevents the replace" do
+ bundle :install, :raise_on_error => false
+
+ expect(err).to match(/The list of sources changed/)
+ end
+ end
+
+ context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is true" do
+ before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "true" }
+
+ it "allows the replace" do
+ bundle :install
+
+ expect(out).to match(/Bundle complete!/)
+ end
+ end
- expect(out).to match(/Bundle complete!/)
+ context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is false" do
+ before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "false" }
+
+ it "prevents the replace" do
+ bundle :install, :raise_on_error => false
+
+ expect(err).to match(/The list of sources changed/)
+ end
end
end
@@ -207,52 +202,40 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "install"
end
- it "installs gems by default to vendor/bundle" do
- bundle "config set deployment true"
- expect do
- bundle "install"
- end.not_to change { bundled_app_lock.mtime }
+ it "installs gems by default to vendor/bundle", :bundler => "< 3" do
+ bundle "install --deployment"
expect(out).to include("vendor/bundle")
end
- it "installs gems to custom path if specified" do
- bundle "config set path vendor/bundle2"
- bundle "config set deployment true"
- bundle "install"
+ it "installs gems to custom path if specified", :bundler => "< 3" do
+ bundle "install --path vendor/bundle2 --deployment"
expect(out).to include("vendor/bundle2")
end
- it "installs gems to custom path if specified, even when configured through ENV" do
- bundle "config set deployment true"
- bundle "install", env: { "BUNDLE_PATH" => "vendor/bundle2" }
- expect(out).to include("vendor/bundle2")
+ it "works with the --deployment flag if you didn't change anything", :bundler => "< 3" do
+ bundle "install --deployment"
end
- it "works with the `frozen` setting" do
- bundle "config set frozen true"
- expect do
- bundle "install"
- end.not_to change { bundled_app_lock.mtime }
+ it "works with the --frozen flag if you didn't change anything", :bundler => "< 3" do
+ bundle "install --frozen"
end
it "works with BUNDLE_FROZEN if you didn't change anything" do
- expect do
- bundle :install, env: { "BUNDLE_FROZEN" => "true" }
- end.not_to change { bundled_app_lock.mtime }
+ bundle :install, :env => { "BUNDLE_FROZEN" => "true" }
end
- it "explodes with the `deployment` setting if you make a change and don't check in the lockfile" do
+ it "explodes with the --deployment flag if you make a change and don't check in the lockfile" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
- expect(err).to include("frozen mode")
+ bundle :install, :raise_on_error => false
+ expect(err).to include("deployment mode")
expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
+ expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have changed in the Gemfile")
end
@@ -260,7 +243,7 @@ RSpec.describe "install in deployment or frozen mode" do
it "works if a path gem is missing but is in a without group" do
build_lib "path_gem"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
gem "path_gem", :path => "#{lib_path("path_gem-1.0")}", :group => :development
G
@@ -270,64 +253,26 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local path .bundle"
bundle "config set --local without development"
bundle "config set --local deployment true"
- bundle :install, env: { "DEBUG" => "1" }
+ bundle :install, :env => { "DEBUG" => "1" }
run "puts :WIN"
expect(out).to eq("WIN")
end
- it "works if a gem is missing, but it's on a different platform" do
- build_repo2
-
+ it "works if a gem is missing, but it's on a different platform, and the Gemfile has no global source", :bundler => "< 3" do
install_gemfile <<-G
- source "https://gem.repo2"
-
- source "https://gem.repo1" do
+ source "#{file_uri_for(gem_repo1)}" do
gem "rake", platform: :#{not_local_tag}
end
G
- bundle :install, env: { "BUNDLE_FROZEN" => "true" }
+ bundle :install, :env => { "BUNDLE_FROZEN" => "true" }
expect(last_command).to be_success
end
- it "shows a good error if a gem is missing from the lockfile" do
- build_repo4 do
- build_gem "foo"
- build_gem "bar"
- end
-
- gemfile <<-G
- source "https://gem.repo4"
-
- gem "foo"
- gem "bar"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- foo (1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- bar
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle :install, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false, artifice: "compact_index"
- expect(err).to include("Your lock file is missing \"bar\", but the lockfile can't be updated because frozen mode is set")
- end
-
it "explodes if a path gem is missing" do
build_lib "path_gem"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
gem "path_gem", :path => "#{lib_path("path_gem-1.0")}", :group => :development
G
@@ -336,49 +281,49 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local path .bundle"
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("The path `#{lib_path("path_gem-1.0")}` does not exist.")
end
- it "can have --frozen set via an environment variable" do
+ it "can have --frozen set via an environment variable", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
ENV["BUNDLE_FROZEN"] = "1"
- bundle "install", raise_on_error: false
- expect(err).to include("frozen mode")
+ bundle "install", :raise_on_error => false
+ expect(err).to include("deployment mode")
expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
+ expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have changed in the Gemfile")
end
it "can have --deployment set via an environment variable" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
ENV["BUNDLE_DEPLOYMENT"] = "true"
- bundle "install", raise_on_error: false
- expect(err).to include("frozen mode")
+ bundle "install", :raise_on_error => false
+ expect(err).to include("deployment mode")
expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
+ expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have changed in the Gemfile")
end
- it "installs gems by default to vendor/bundle when deployment mode is set via an environment variable" do
+ it "installs gems by default to vendor/bundle when deployment mode is set via an environment variable", :bundler => "< 3" do
ENV["BUNDLE_DEPLOYMENT"] = "true"
bundle "install"
expect(out).to include("vendor/bundle")
end
- it "installs gems to custom path when deployment mode is set via an environment variable " do
+ it "installs gems to custom path when deployment mode is set via an environment variable ", :bundler => "< 3" do
ENV["BUNDLE_DEPLOYMENT"] = "true"
ENV["BUNDLE_PATH"] = "vendor/bundle2"
bundle "install"
@@ -387,119 +332,87 @@ RSpec.describe "install in deployment or frozen mode" do
it "can have --frozen set to false via an environment variable" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
ENV["BUNDLE_FROZEN"] = "false"
ENV["BUNDLE_DEPLOYMENT"] = "false"
bundle "install"
- expect(out).not_to include("frozen mode")
+ expect(out).not_to include("deployment mode")
expect(out).not_to include("You have added to the Gemfile")
- expect(out).not_to include("* myrack-obama")
+ expect(out).not_to include("* rack-obama")
end
- it "explodes if you replace a gem and don't check in the lockfile" do
+ it "explodes if you remove a gem and don't check in the lockfile" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
- expect(err).to include("frozen mode")
+ bundle :install, :raise_on_error => false
+ expect(err).to include("deployment mode")
expect(err).to include("You have added to the Gemfile:\n* activesupport\n\n")
- expect(err).to include("You have deleted from the Gemfile:\n* myrack")
- expect(err).not_to include("You have changed in the Gemfile")
- end
-
- it "explodes if you remove a gem and don't check in the lockfile" do
- gemfile 'source "https://gem.repo1"'
-
- bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
- expect(err).to include("Some dependencies were deleted")
- expect(err).to include("frozen mode")
- expect(err).to include("You have deleted from the Gemfile:\n* myrack")
+ expect(err).to include("You have deleted from the Gemfile:\n* rack")
expect(err).not_to include("You have changed in the Gemfile")
end
it "explodes if you add a source" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "git://hubz.com"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "git://hubz.com"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
- expect(err).to include("frozen mode")
+ bundle :install, :raise_on_error => false
+ expect(err).to include("deployment mode")
expect(err).not_to include("You have added to the Gemfile")
- expect(err).to include("You have changed in the Gemfile:\n* myrack from `no specified source` to `git://hubz.com`")
+ expect(err).to include("You have changed in the Gemfile:\n* rack from `no specified source` to `git://hubz.com`")
end
- it "explodes if you change a source from git to the default" do
- build_git "myrack"
+ it "explodes if you change a source" do
+ build_git "rack"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-1.0")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-1.0")}"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
- expect(err).to include("frozen mode")
+ bundle :install, :raise_on_error => false
+ expect(err).to include("deployment mode")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have added to the Gemfile")
- expect(err).to include("You have changed in the Gemfile:\n* myrack from `#{lib_path("myrack-1.0")}` to `no specified source`")
+ expect(err).to include("You have changed in the Gemfile:\n* rack from `#{lib_path("rack-1.0")}` to `no specified source`")
end
- it "explodes if you change a source from git to the default, in presence of other git sources" do
- build_lib "foo", path: lib_path("myrack/foo")
- build_git "myrack", path: lib_path("myrack")
+ it "explodes if you change a source" do
+ build_lib "foo", :path => lib_path("rack/foo")
+ build_git "rack", :path => lib_path("rack")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack")}"
- gem "foo", :git => "#{lib_path("myrack")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack")}"
+ gem "foo", :git => "#{lib_path("rack")}"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "foo", :git => "#{lib_path("myrack")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "foo", :git => "#{lib_path("rack")}"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
- expect(err).to include("frozen mode")
- expect(err).to include("You have changed in the Gemfile:\n* myrack from `#{lib_path("myrack")}` to `no specified source`")
- expect(err).not_to include("You have added to the Gemfile")
- expect(err).not_to include("You have deleted from the Gemfile")
- end
-
- it "explodes if you change a source from path to git" do
- build_git "myrack", path: lib_path("myrack")
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :path => "#{lib_path("myrack")}"
- G
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "https:/my-git-repo-for-myrack"
- G
-
- bundle "config set --local frozen true"
- bundle :install, raise_on_error: false
- expect(err).to include("frozen mode")
- expect(err).to include("You have changed in the Gemfile:\n* myrack from `#{lib_path("myrack")}` to `https:/my-git-repo-for-myrack`")
+ bundle :install, :raise_on_error => false
+ expect(err).to include("deployment mode")
+ expect(err).to include("You have changed in the Gemfile:\n* rack from `#{lib_path("rack")}` to `no specified source`")
expect(err).not_to include("You have added to the Gemfile")
expect(err).not_to include("You have deleted from the Gemfile")
end
@@ -510,30 +423,30 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local deployment true"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
+ gem "rack-obama"
G
- run "require 'myrack'", 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)
+ run "require 'rack'", :raise_on_error => false
+ expect(err).to include strip_whitespace(<<-E).strip
+The dependencies in your gemfile changed
- You have added to the Gemfile:
- * myrack (= 1.0.0)
- * myrack-obama
+You have added to the Gemfile:
+* rack (= 1.0.0)
+* rack-obama
- You have deleted from the Gemfile:
- * myrack
+You have deleted from the Gemfile:
+* rack
E
end
end
context "with path in Gemfile and packed" do
it "works fine after bundle package and bundle install --local" do
- build_lib "foo", path: lib_path("foo")
+ build_lib "foo", :path => lib_path("foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
@@ -550,7 +463,7 @@ RSpec.describe "install in deployment or frozen mode" do
simulate_new_machine
bundle "config set --local deployment true"
bundle "install --verbose"
- expect(out).not_to include("but the lockfile can't be updated because frozen mode is set")
+ expect(out).not_to include("You are trying to install in deployment mode after changing your Gemfile")
expect(out).not_to include("You have added to the Gemfile")
expect(out).not_to include("You have deleted from the Gemfile")
expect(out).to include("vendor/cache/foo")
diff --git a/spec/bundler/install/failure_spec.rb b/spec/bundler/install/failure_spec.rb
index 2c2773e849..4a9c33754f 100644
--- a/spec/bundler/install/failure_spec.rb
+++ b/spec/bundler/install/failure_spec.rb
@@ -14,8 +14,8 @@ RSpec.describe "bundle install" do
end
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
G
expect(err).to start_with("Gem::Ext::BuildError: ERROR: Failed to build gem native extension.")
@@ -39,8 +39,8 @@ In Gemfile:
end
it "removes the downloaded .gem" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo4"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
G
diff --git a/spec/bundler/install/gemfile/eval_gemfile_spec.rb b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
index a507e52485..02283291b4 100644
--- a/spec/bundler/install/gemfile/eval_gemfile_spec.rb
+++ b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
@@ -2,7 +2,7 @@
RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
before do
- build_lib("gunks", path: bundled_app("gems/gunks")) do |s|
+ build_lib("gunks", :path => bundled_app.join("gems/gunks")) do |s|
s.name = "gunks"
s.version = "0.0.1"
end
@@ -10,21 +10,21 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
context "eval-ed Gemfile points to an internal gemspec" do
before do
- gemfile "Gemfile-other", <<-G
- source "https://gem.repo1"
+ create_file "Gemfile-other", <<-G
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => 'gems/gunks'
G
end
it "installs the gemspec specified gem" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile 'Gemfile-other'
G
expect(out).to include("Resolving dependencies")
expect(out).to include("Bundle complete")
- expect(the_bundle).to include_gem "gunks 0.0.1", source: "path@#{bundled_app("gems", "gunks")}"
+ expect(the_bundle).to include_gem "gunks 0.0.1", :source => "path@#{bundled_app("gems", "gunks")}"
end
end
@@ -36,12 +36,12 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
build_gem "zip-zip", "0.3"
end
- gemfile bundled_app("gems/Gemfile"), <<-G
- source "https://gem.repo2"
+ create_file bundled_app("gems/Gemfile"), <<-G
+ source "#{file_uri_for(gem_repo2)}"
gemspec :path => "\#{__dir__}/gunks"
- source "https://gem.repo2" do
+ source "#{file_uri_for(gem_repo2)}" do
gem "zip-zip"
end
G
@@ -49,7 +49,7 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
it "installs and finds gems correctly" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
@@ -64,14 +64,14 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
context "eval-ed Gemfile has relative-path gems" do
before do
- build_lib("a", path: bundled_app("gems/a"))
- gemfile bundled_app("nested/Gemfile-nested"), <<-G
- source "https://gem.repo1"
+ build_lib("a", :path => bundled_app("gems/a"))
+ create_file bundled_app("nested/Gemfile-nested"), <<-G
+ source "#{file_uri_for(gem_repo1)}"
gem "a", :path => "../gems/a"
G
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "nested/Gemfile-nested"
G
end
@@ -95,28 +95,28 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
it "installs the gemspec specified gem" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile 'other/Gemfile-other'
gemspec :path => 'gems/gunks'
G
expect(out).to include("Resolving dependencies")
expect(out).to include("Bundle complete")
- expect(the_bundle).to include_gem "gunks 0.0.1", source: "path@#{bundled_app("gems", "gunks")}"
+ expect(the_bundle).to include_gem "gunks 0.0.1", :source => "path@#{bundled_app("gems", "gunks")}"
end
end
context "eval-ed Gemfile references other gemfiles" do
it "works with relative paths" do
- gemfile "other/Gemfile-other", "gem 'myrack'"
- gemfile "other/Gemfile", "eval_gemfile 'Gemfile-other'"
- gemfile "Gemfile-alt", <<-G
- source "https://gem.repo1"
+ create_file "other/Gemfile-other", "gem 'rack'"
+ create_file "other/Gemfile", "eval_gemfile 'Gemfile-other'"
+ create_file "Gemfile-alt", <<-G
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "other/Gemfile"
G
install_gemfile "eval_gemfile File.expand_path('Gemfile-alt')"
- expect(the_bundle).to include_gem "myrack 1.0.0"
+ expect(the_bundle).to include_gem "rack 1.0.0"
end
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 926e7527e6..0e9f1f0292 100644
--- a/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
+++ b/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
@@ -5,68 +5,77 @@ RSpec.describe "bundle install with force_ruby_platform DSL option", :jruby do
before do
build_repo4 do
# Build a gem with platform specific versions
- build_gem("platform_specific")
+ build_gem("platform_specific") do |s|
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
build_gem("platform_specific") do |s|
s.platform = Bundler.local_platform
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
end
# Build the exact same gem with a different name to compare using vs not using the option
- build_gem("platform_specific_forced")
+ build_gem("platform_specific_forced") do |s|
+ s.write "lib/platform_specific_forced.rb", "PLATFORM_SPECIFIC_FORCED = '1.0.0 RUBY'"
+ end
build_gem("platform_specific_forced") do |s|
s.platform = Bundler.local_platform
+ s.write "lib/platform_specific_forced.rb", "PLATFORM_SPECIFIC_FORCED = '1.0.0 #{Bundler.local_platform}'"
end
end
end
it "pulls the pure ruby variant of the given gem" do
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "platform_specific_forced", :force_ruby_platform => true
gem "platform_specific"
G
- expect(the_bundle).to include_gems "platform_specific_forced 1.0 ruby"
- expect(the_bundle).to include_gems "platform_specific 1.0 #{Bundler.local_platform}"
+ expect(the_bundle).to include_gems "platform_specific_forced 1.0.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 #{Bundler.local_platform}"
end
it "still respects a global `force_ruby_platform` config" do
- install_gemfile <<-G, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
- source "https://gem.repo4"
+ install_gemfile <<-G, :env => { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
gem "platform_specific_forced", :force_ruby_platform => true
gem "platform_specific"
G
- expect(the_bundle).to include_gems "platform_specific_forced 1.0 ruby"
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific_forced 1.0.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 RUBY"
end
end
context "when also a transitive dependency" do
before do
build_repo4 do
- build_gem("depends_on_platform_specific") {|s| s.add_dependency "platform_specific" }
+ build_gem("depends_on_platform_specific") {|s| s.add_runtime_dependency "platform_specific" }
- build_gem("platform_specific")
+ build_gem("platform_specific") do |s|
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
build_gem("platform_specific") do |s|
s.platform = Bundler.local_platform
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
end
end
end
it "still pulls the ruby variant" do
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "depends_on_platform_specific"
gem "platform_specific", :force_ruby_platform => true
G
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 RUBY"
end
end
@@ -74,63 +83,36 @@ RSpec.describe "bundle install with force_ruby_platform DSL option", :jruby do
before do
build_repo4 do
build_gem("depends_on_platform_specific") do |s|
- s.add_dependency "platform_specific"
+ s.add_runtime_dependency "platform_specific"
+ s.write "lib/depends_on_platform_specific.rb", "DEPENDS_ON_PLATFORM_SPECIFIC = '1.0.0 RUBY'"
end
build_gem("depends_on_platform_specific") do |s|
- s.add_dependency "platform_specific"
+ s.add_runtime_dependency "platform_specific"
s.platform = Bundler.local_platform
+ s.write "lib/depends_on_platform_specific.rb", "DEPENDS_ON_PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
end
- build_gem("platform_specific")
+ build_gem("platform_specific") do |s|
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
build_gem("platform_specific") do |s|
s.platform = Bundler.local_platform
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
end
end
end
it "ignores ruby variants for the transitive dependencies" do
- install_gemfile <<-G, env: { "DEBUG_RESOLVER" => "true" }
- source "https://gem.repo4"
+ install_gemfile <<-G, :env => { "DEBUG_RESOLVER" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
gem "depends_on_platform_specific", :force_ruby_platform => true
G
- expect(the_bundle).to include_gems "depends_on_platform_specific 1.0 ruby"
- expect(the_bundle).to include_gems "platform_specific 1.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
- skip "Can't simulate platform reliably on JRuby, installing a platform specific gem fails to activate io-wait because only the -java version is present, and we're simulating a different platform" if RUBY_ENGINE == "jruby"
-
- lockfile <<-L
- GEM
- remote: https://gem.repo4
- specs:
- platform_specific (1.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- platform_specific
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- simulate_platform "x86-darwin-100" do
- system_gems "platform_specific-1.0-x86-darwin-100", path: default_bundle_path
-
- install_gemfile <<-G, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, artifice: "compact_index"
- source "https://gem.repo4"
-
- gem "platform_specific", :force_ruby_platform => true
- G
-
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
- end
+ 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
end
end
diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb
index 5610a6f05b..7e2e7c345a 100644
--- a/spec/bundler/install/gemfile/gemspec_spec.rb
+++ b/spec/bundler/install/gemfile/gemspec_spec.rb
@@ -28,46 +28,36 @@ RSpec.describe "bundle install from an existing gemspec" do
x64_mingw_archs.join("\n ")
end
- def x64_mingw_checksums(checksums)
- x64_mingw_archs.each do |arch|
- if arch == "x64-mingw-ucrt"
- checksums.no_checksum "platform_specific", "1.0", arch
- else
- checksums.checksum gem_repo2, "platform_specific", "1.0", arch
- end
- end
- end
-
it "should install runtime and development dependencies" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
end
install_gemfile <<-G
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development
end
it "that is hidden should install runtime and development dependencies" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
end
- FileUtils.mv tmp("foo", "foo.gemspec"), tmp("foo", ".gemspec")
+ FileUtils.mv tmp.join("foo", "foo.gemspec"), tmp.join("foo", ".gemspec")
install_gemfile <<-G
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development
end
it "should handle a list of requirements" do
@@ -76,151 +66,151 @@ RSpec.describe "bundle install from an existing gemspec" do
build_gem "baz", "1.1"
end
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
s.add_dependency "baz", ">= 1.0", "< 1.1"
end
install_gemfile <<-G
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
expect(the_bundle).to include_gems "baz 1.0"
end
it "should raise if there are no gemspecs available" do
- build_lib("foo", path: tmp("foo"), gemspec: false)
+ build_lib("foo", :path => tmp.join("foo"), :gemspec => false)
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
- expect(err).to match(/There are no gemspecs at #{tmp("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
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("foo2.gemspec", build_spec("foo", "4.0").first.to_ruby)
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
- expect(err).to match(/There are multiple gemspecs at #{tmp("foo")}/)
+ expect(err).to match(/There are multiple gemspecs at #{tmp.join('foo')}/)
end
it "should pick a specific gemspec" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("foo2.gemspec", "")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
end
install_gemfile(<<-G)
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development
end
it "should use a specific group for development dependencies" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("foo2.gemspec", "")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
end
install_gemfile(<<-G)
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}', :name => 'foo', :development_group => :dev
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo', :development_group => :dev
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).not_to include_gems "bar-dev 1.0.0", groups: :development
- expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :dev
+ expect(the_bundle).not_to include_gems "bar-dev 1.0.0", :groups => :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :dev
end
it "should match a lockfile even if the gemspec defines development dependencies" do
- build_lib("foo", path: tmp("foo")) do |s|
- s.write("Gemfile", "source 'https://gem.repo1'\ngemspec")
+ build_lib("foo", :path => tmp.join("foo")) do |s|
+ s.write("Gemfile", "source '#{file_uri_for(gem_repo1)}'\ngemspec")
s.add_dependency "actionpack", "=2.3.2"
- s.add_development_dependency "rake", rake_version
+ s.add_development_dependency "rake", "=13.0.1"
end
- bundle "install", dir: tmp("foo"), artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ bundle "install", :dir => tmp.join("foo")
# This should really be able to rely on $stderr, but, it's not written
# right, so we can't. In fact, this is a bug negation test, and so it'll
# ghost pass in future, and will only catch a regression if the message
# doesn't change. Exit codes should be used correctly (they can be more
# than just 0 and 1).
bundle "config set --local deployment true"
- output = bundle("install", dir: tmp("foo"), artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s })
+ output = bundle("install", :dir => tmp.join("foo"))
expect(output).not_to match(/You have added to the Gemfile/)
expect(output).not_to match(/You have deleted from the Gemfile/)
- expect(output).not_to match(/the lockfile can't be updated because frozen mode is set/)
+ expect(output).not_to match(/install in deployment mode after changing/)
end
it "should match a lockfile without needing to re-resolve" do
- build_lib("foo", path: tmp("foo")) do |s|
- s.add_dependency "myrack"
+ build_lib("foo", :path => tmp.join("foo")) do |s|
+ s.add_dependency "rack"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}'
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
- bundle "install", verbose: true
+ bundle "install", :verbose => true
message = "Found no changes, using resolution from the lockfile"
expect(out.scan(message).size).to eq(1)
end
it "should match a lockfile without needing to re-resolve with development dependencies" do
- simulate_platform java do
- build_lib("foo", path: tmp("foo")) do |s|
- s.add_dependency "myrack"
- s.add_development_dependency "thin"
- end
+ simulate_platform java
- install_gemfile <<-G
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}'
- G
+ build_lib("foo", :path => tmp.join("foo")) do |s|
+ s.add_dependency "rack"
+ s.add_development_dependency "thin"
+ end
- bundle "install", verbose: true
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}'
+ G
- message = "Found no changes, using resolution from the lockfile"
- expect(out.scan(message).size).to eq(1)
- end
+ bundle "install", :verbose => true
+
+ message = "Found no changes, using resolution from the lockfile"
+ expect(out.scan(message).size).to eq(1)
end
it "should match a lockfile on non-ruby platforms with a transitive platform dependency", :jruby_only do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.add_dependency "platform_specific"
end
- system_gems "platform_specific-1.0-java", path: default_bundle_path
+ system_gems "platform_specific-1.0-java", :path => default_bundle_path
install_gemfile <<-G
- gemspec :path => '#{tmp("foo")}'
+ gemspec :path => '#{tmp.join("foo")}'
G
- bundle "update --bundler", artifice: "compact_index", verbose: true
- expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 java"
+ bundle "update --bundler", :artifice => "compact_index", :verbose => true
+ expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 JAVA"
end
it "should evaluate the gemspec in its directory" do
- build_lib("foo", path: tmp("foo"))
- File.open(tmp("foo/foo.gemspec"), "w") do |s|
- s.write "raise 'ahh' unless Dir.pwd == '#{tmp("foo")}'"
+ build_lib("foo", :path => tmp.join("foo"))
+ File.open(tmp.join("foo/foo.gemspec"), "w") do |s|
+ s.write "raise 'ahh' unless Dir.pwd == '#{tmp.join("foo")}'"
end
- install_gemfile <<-G, raise_on_error: false
- gemspec :path => '#{tmp("foo")}'
+ install_gemfile <<-G, :raise_on_error => false
+ gemspec :path => '#{tmp.join("foo")}'
G
expect(last_command.stdboth).not_to include("ahh")
end
@@ -231,16 +221,16 @@ RSpec.describe "bundle install from an existing gemspec" do
#
# issue was caused by rubygems having an unresolved gem during a require,
# so emulate that
- system_gems %w[myrack-1.0.0 myrack-0.9.1 myrack-obama-1.0]
+ system_gems %w[rack-1.0.0 rack-0.9.1 rack-obama-1.0]
- build_lib("foo", path: bundled_app)
+ build_lib("foo", :path => bundled_app)
gemspec = bundled_app("foo.gemspec").read
bundled_app("foo.gemspec").open("w") do |f|
- f.write "#{gemspec.strip}.tap { gem 'myrack-obama'; require 'myrack/obama' }"
+ f.write "#{gemspec.strip}.tap { gem 'rack-obama'; require 'rack/obama' }"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
@@ -248,26 +238,26 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "allows conflicts" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.version = "1.0.0"
s.add_dependency "bar", "= 1.0.0"
end
- build_gem "deps", to_bundle: true do |s|
+ build_gem "deps", :to_bundle => true do |s|
s.add_dependency "foo", "= 0.0.1"
end
- build_gem "foo", "0.0.1", to_bundle: true
+ build_gem "foo", "0.0.1", :to_bundle => true
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "deps"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
expect(the_bundle).to include_gems "foo 1.0.0"
end
it "does not break Gem.finish_resolve with conflicts" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.version = "1.0.0"
s.add_dependency "bar", "= 1.0.0"
end
@@ -279,9 +269,9 @@ RSpec.describe "bundle install from an existing gemspec" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "deps"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
expect(the_bundle).to include_gems "foo 1.0.0"
@@ -291,14 +281,14 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "handles downgrades" do
- build_lib "omg", "2.0", path: lib_path("omg")
+ build_lib "omg", "2.0", :path => lib_path("omg")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("omg")}"
G
- build_lib "omg", "1.0", path: lib_path("omg")
+ build_lib "omg", "1.0", :path => lib_path("omg")
bundle :install
@@ -308,23 +298,23 @@ RSpec.describe "bundle install from an existing gemspec" do
context "in deployment mode" do
context "when the lockfile was not updated after a change to the gemspec's dependencies" do
it "reports that installation failed" do
- build_lib "cocoapods", path: bundled_app do |s|
+ build_lib "cocoapods", :path => bundled_app do |s|
s.add_dependency "activesupport", ">= 1"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
expect(the_bundle).to include_gems("cocoapods 1.0", "activesupport 2.3.5")
- build_lib "cocoapods", path: bundled_app do |s|
+ build_lib "cocoapods", :path => bundled_app do |s|
s.add_dependency "activesupport", ">= 1.0.1"
end
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("changed")
end
@@ -334,24 +324,24 @@ RSpec.describe "bundle install from an existing gemspec" do
context "when child gemspecs conflict with a released gemspec" do
before do
# build the "parent" gem that depends on another gem in the same repo
- build_lib "source_conflict", path: bundled_app do |s|
- s.add_dependency "myrack_middleware"
+ build_lib "source_conflict", :path => bundled_app do |s|
+ s.add_dependency "rack_middleware"
end
# build the "child" gem that is the same version as a released gem, but
# has completely different and conflicting dependency requirements
- build_lib "myrack_middleware", "1.0", path: bundled_app("myrack_middleware") do |s|
- s.add_dependency "myrack", "1.0" # anything other than 0.9.1
+ build_lib "rack_middleware", "1.0", :path => bundled_app("rack_middleware") do |s|
+ s.add_dependency "rack", "1.0" # anything other than 0.9.1
end
end
it "should install the child gemspec's deps" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
@@ -359,8 +349,8 @@ RSpec.describe "bundle install from an existing gemspec" do
let(:source_uri) { "http://localgemserver.test" }
before do
- build_lib("foo", path: tmp("foo")) do |s|
- s.add_dependency "myrack", "=1.0.0"
+ build_lib("foo", :path => tmp.join("foo")) do |s|
+ s.add_dependency "rack", "=1.0.0"
end
gemfile <<-G
@@ -368,28 +358,24 @@ RSpec.describe "bundle install from an existing gemspec" do
gemspec :path => "../foo"
G
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
-
lockfile <<-L
PATH
remote: ../foo
specs:
foo (1.0)
- myrack (= 1.0.0)
+ rack (= 1.0.0)
GEM
remote: #{source_uri}
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{generic_local_platform}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -398,9 +384,9 @@ RSpec.describe "bundle install from an existing gemspec" do
context "using JRuby with explicit platform", :jruby_only do
before do
create_file(
- tmp("foo", "foo-java.gemspec"),
+ tmp.join("foo", "foo-java.gemspec"),
build_spec("foo", "1.0", "java") do
- dep "myrack", "=1.0.0"
+ dep "rack", "=1.0.0"
@spec.authors = "authors"
@spec.summary = "summary"
end.first.to_ruby
@@ -408,16 +394,16 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "should install" do
- results = bundle "install", artifice: "endpoint"
- expect(results).to include("Installing myrack 1.0.0")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ results = bundle "install", :artifice => "endpoint"
+ expect(results).to include("Installing rack 1.0.0")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
it "should install", :jruby do
- results = bundle "install", artifice: "endpoint"
- expect(results).to include("Installing myrack 1.0.0")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ results = bundle "install", :artifice => "endpoint"
+ expect(results).to include("Installing rack 1.0.0")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
context "bundled for multiple platforms" do
@@ -430,7 +416,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
end
- build_lib "foo", path: bundled_app do |s|
+ build_lib "foo", :path => bundled_app do |s|
if platform_specific_type == :runtime
s.add_runtime_dependency dependency
elsif platform_specific_type == :development
@@ -441,7 +427,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gemspec
G
@@ -461,16 +447,8 @@ 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"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0", "java"
- x64_mingw_checksums(c)
- end
-
- expect(lockfile).to eq <<~L
+ expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
+ expect(lockfile).to eq strip_whitespace(<<-L)
PATH
remote: .
specs:
@@ -478,7 +456,7 @@ RSpec.describe "bundle install from an existing gemspec" do
platform_specific
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
platform_specific (1.0)
platform_specific (1.0-java)
@@ -491,7 +469,7 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -502,23 +480,15 @@ RSpec.describe "bundle install from an existing gemspec" do
let(:platform_specific_type) { :development }
it "keeps all platform dependencies in the lockfile" do
- expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 ruby"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0", "java"
- x64_mingw_checksums(c)
- end
-
- expect(lockfile).to eq <<~L
+ expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
+ expect(lockfile).to eq strip_whitespace(<<-L)
PATH
remote: .
specs:
foo (1.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
platform_specific (1.0)
platform_specific (1.0-java)
@@ -532,7 +502,7 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
foo!
platform_specific
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -544,24 +514,15 @@ RSpec.describe "bundle install from an existing gemspec" do
let(:dependency) { "indirect_platform_specific" }
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"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo2, "indirect_platform_specific", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0", "java"
- x64_mingw_checksums(c)
- end
-
- expect(lockfile).to eq <<~L
+ expect(the_bundle).to include_gems "foo 1.0", "indirect_platform_specific 1.0", "platform_specific 1.0 RUBY"
+ expect(lockfile).to eq strip_whitespace(<<-L)
PATH
remote: .
specs:
foo (1.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
indirect_platform_specific (1.0)
platform_specific
@@ -577,7 +538,7 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
foo!
indirect_platform_specific
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -589,10 +550,10 @@ RSpec.describe "bundle install from an existing gemspec" do
context "with multiple platforms" do
before do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.version = "1.0.0"
- s.add_development_dependency "myrack"
- s.write "foo-universal-java.gemspec", build_spec("foo", "1.0.0", "universal-java") {|sj| sj.runtime "myrack", "1.0.0" }.first.to_ruby
+ s.add_development_dependency "rack"
+ s.write "foo-universal-java.gemspec", build_spec("foo", "1.0.0", "universal-java") {|sj| sj.runtime "rack", "1.0.0" }.first.to_ruby
end
end
@@ -600,11 +561,11 @@ RSpec.describe "bundle install from an existing gemspec" do
bundle "config set --local force_ruby_platform true"
install_gemfile <<-G
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
- expect(the_bundle).to include_gems "foo 1.0.0", "myrack 1.0.0"
+ expect(the_bundle).to include_gems "foo 1.0.0", "rack 1.0.0"
end
it "installs the ruby platform gemspec and skips dev deps with `without development` configured" do
@@ -612,18 +573,18 @@ RSpec.describe "bundle install from an existing gemspec" do
bundle "config set --local without development"
install_gemfile <<-G
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
expect(the_bundle).to include_gem "foo 1.0.0"
- expect(the_bundle).not_to include_gem "myrack"
+ expect(the_bundle).not_to include_gem "rack"
end
end
context "with multiple platforms and resolving for more specific platforms" do
before do
- build_lib("chef", path: tmp("chef")) do |s|
+ build_lib("chef", :path => tmp.join("chef")) do |s|
s.version = "17.1.17"
s.write "chef-universal-mingw32.gemspec", build_spec("chef", "17.1.17", "universal-mingw32") {|sw| sw.runtime "win32-api", "~> 1.5.3" }.first.to_ruby
end
@@ -637,16 +598,10 @@ RSpec.describe "bundle install from an existing gemspec" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gemspec :path => "../chef"
G
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "chef", "17.1.17"
- c.no_checksum "chef", "17.1.17", "universal-mingw32"
- c.checksum gem_repo4, "win32-api", "1.5.3", "universal-mingw32"
- end
-
initial_lockfile = <<~L
PATH
remote: ../chef
@@ -656,7 +611,7 @@ RSpec.describe "bundle install from an existing gemspec" do
win32-api (~> 1.5.3)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
win32-api (1.5.3-universal-mingw32)
@@ -667,7 +622,7 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
chef!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -682,7 +637,7 @@ RSpec.describe "bundle install from an existing gemspec" do
context "with multiple locked platforms" do
before do
- build_lib("activeadmin", path: tmp("activeadmin")) do |s|
+ build_lib("activeadmin", :path => tmp.join("activeadmin")) do |s|
s.version = "2.9.0"
s.add_dependency "railties", ">= 5.2", "< 6.2"
end
@@ -696,7 +651,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gemspec :path => "../activeadmin"
gem "jruby-openssl", :platform => :jruby
G
@@ -705,12 +660,6 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "does not remove the platform specific specs from the lockfile when re-resolving due to gemspec changes" do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "activeadmin", "2.9.0"
- c.checksum gem_repo4, "jruby-openssl", "0.10.7", "java"
- c.checksum gem_repo4, "railties", "6.1.4"
- end
-
expect(lockfile).to eq <<~L
PATH
remote: ../activeadmin
@@ -719,23 +668,23 @@ RSpec.describe "bundle install from an existing gemspec" do
railties (>= 5.2, < 6.2)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
jruby-openssl (0.10.7-java)
railties (6.1.4)
PLATFORMS
- #{lockfile_platforms("java")}
+ #{lockfile_platforms_for(["java", specific_local_platform])}
DEPENDENCIES
activeadmin!
jruby-openssl
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
- gemspec = tmp("activeadmin/activeadmin.gemspec")
+ gemspec = tmp.join("activeadmin/activeadmin.gemspec")
File.write(gemspec, File.read(gemspec).sub(">= 5.2", ">= 6.0"))
previous_lockfile = lockfile
diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb
index 83b3c06cbe..b6ea32819b 100644
--- a/spec/bundler/install/gemfile/git_spec.rb
+++ b/spec/bundler/install/gemfile/git_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe "bundle install with git sources" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -26,22 +26,15 @@ RSpec.describe "bundle install with git sources" do
expect(out).to eq("WIN")
end
- it "caches the git repo", bundler: "< 3" do
- expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes size: 1
- end
-
- it "does not write to cache on bundler/setup" do
- cache_path = default_bundle_path("cache")
- FileUtils.rm_rf(cache_path)
- ruby "require 'bundler/setup'"
- expect(cache_path).not_to exist
+ it "caches the git repo", :bundler => "< 3" do
+ expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes :size => 1
end
it "caches the git repo globally and properly uses the cached repo on the next invocation" do
simulate_new_machine
bundle "config set global_gem_cache true"
bundle :install
- expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes size: 1
+ expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes :size => 1
bundle "install --verbose"
expect(err).to be_empty
@@ -59,7 +52,7 @@ RSpec.describe "bundle install with git sources" do
bundle "update foo"
sha = git.ref_for("main", 11)
- spec_file = default_bundle_path("bundler/gems/foo-1.0-#{sha}/foo.gemspec")
+ spec_file = default_bundle_path.join("bundler/gems/foo-1.0-#{sha}/foo.gemspec")
expect(spec_file).to exist
ruby_code = Gem::Specification.load(spec_file.to_s).to_ruby
file_code = File.read(spec_file)
@@ -69,8 +62,8 @@ RSpec.describe "bundle install with git sources" do
it "does not update the git source implicitly" do
update_git "foo"
- install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
- source "https://gem.repo1"
+ install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -92,8 +85,8 @@ RSpec.describe "bundle install with git sources" do
it "complains if pinned specs don't exist in the git repo" do
build_git "foo"
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.1", :git => "#{lib_path("foo-1.0")}"
G
@@ -105,8 +98,8 @@ RSpec.describe "bundle install with git sources" do
s.platform = "java"
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
platforms :jruby do
gem "only_java", "1.2", :git => "#{lib_path("only_java-1.0-java")}"
end
@@ -125,8 +118,8 @@ RSpec.describe "bundle install with git sources" do
s.write "only_java1-0.gemspec", File.read("#{lib_path("only_java-1.0-java")}/only_java.gemspec")
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
platforms :jruby do
gem "only_java", "1.2", :git => "#{lib_path("only_java-1.1-java")}"
end
@@ -141,7 +134,7 @@ RSpec.describe "bundle install with git sources" do
FileUtils.mv bundled_app, tmp("bundled_app.bck")
- expect(the_bundle).to include_gems "foo 1.0", dir: tmp("bundled_app.bck")
+ expect(the_bundle).to include_gems "foo 1.0", :dir => tmp("bundled_app.bck")
end
it "can still install after moving the application directory" do
@@ -150,20 +143,20 @@ RSpec.describe "bundle install with git sources" do
FileUtils.mv bundled_app, tmp("bundled_app.bck")
- update_git "foo", "1.1", path: lib_path("foo-1.0")
+ update_git "foo", "1.1", :path => lib_path("foo-1.0")
gemfile tmp("bundled_app.bck/Gemfile"), <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
- gem "myrack", "1.0"
+ gem "rack", "1.0"
G
- bundle "update foo", dir: tmp("bundled_app.bck")
+ bundle "update foo", :dir => tmp("bundled_app.bck")
- expect(the_bundle).to include_gems "foo 1.1", "myrack 1.0", dir: tmp("bundled_app.bck")
+ expect(the_bundle).to include_gems "foo 1.1", "rack 1.0", :dir => tmp("bundled_app.bck")
end
end
@@ -171,8 +164,8 @@ RSpec.describe "bundle install with git sources" do
before do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
git "#{lib_path("foo-1.0")}" do
# this page left intentionally blank
@@ -182,7 +175,7 @@ RSpec.describe "bundle install with git sources" do
it "does not explode" do
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
@@ -195,7 +188,7 @@ RSpec.describe "bundle install with git sources" do
it "works" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => "#{@revision}" do
gem "foo"
end
@@ -212,7 +205,7 @@ RSpec.describe "bundle install with git sources" do
it "works when the revision is a symbol" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => #{@revision.to_sym.inspect} do
gem "foo"
end
@@ -229,14 +222,14 @@ RSpec.describe "bundle install with git sources" do
it "works when an abbreviated revision is added after an initial, potentially shallow clone" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem "foo"
end
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => #{@revision[0..7].inspect} do
gem "foo"
end
@@ -245,21 +238,21 @@ RSpec.describe "bundle install with git sources" do
it "works when a tag that does not look like a commit hash is used as the value of :ref" do
build_git "foo"
- @remote = build_git("bar", bare: true)
- update_git "foo", remote: @remote.path
- update_git "foo", push: "main"
+ @remote = build_git("bar", :bare => true)
+ update_git "foo", :remote => file_uri_for(@remote.path)
+ update_git "foo", :push => "main"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{@remote.path}"
G
# Create a new tag on the remote that needs fetching
- update_git "foo", tag: "v1.0.0"
- update_git "foo", push: "v1.0.0"
+ update_git "foo", :tag => "v1.0.0"
+ update_git "foo", :push => "v1.0.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{@remote.path}", :ref => "v1.0.0"
G
@@ -268,19 +261,19 @@ RSpec.describe "bundle install with git sources" do
it "works when the revision is a non-head ref" do
# want to ensure we don't fallback to main
- update_git "foo", path: lib_path("foo-1.0") do |s|
+ update_git "foo", :path => lib_path("foo-1.0") do |s|
s.write("lib/foo.rb", "raise 'FAIL'")
end
- git("update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", lib_path("foo-1.0"))
+ sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", :dir => lib_path("foo-1.0"))
# want to ensure we don't fallback to HEAD
- update_git "foo", path: lib_path("foo-1.0"), branch: "rando" do |s|
+ update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s|
s.write("lib/foo.rb", "raise 'FAIL_FROM_RANDO'")
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => "refs/bundler/1" do
gem "foo"
end
@@ -297,26 +290,26 @@ RSpec.describe "bundle install with git sources" do
it "works when the revision is a non-head ref and it was previously downloaded" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem "foo"
end
G
# want to ensure we don't fallback to main
- update_git "foo", path: lib_path("foo-1.0") do |s|
+ update_git "foo", :path => lib_path("foo-1.0") do |s|
s.write("lib/foo.rb", "raise 'FAIL'")
end
- git("update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", lib_path("foo-1.0"))
+ sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", :dir => lib_path("foo-1.0"))
# want to ensure we don't fallback to HEAD
- update_git "foo", path: lib_path("foo-1.0"), branch: "rando" do |s|
+ update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s|
s.write("lib/foo.rb", "raise 'FAIL_FROM_RANDO'")
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => "refs/bundler/1" do
gem "foo"
end
@@ -332,21 +325,21 @@ RSpec.describe "bundle install with git sources" do
end
it "does not download random non-head refs" do
- git("update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", lib_path("foo-1.0"))
+ sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", :dir => lib_path("foo-1.0"))
bundle "config set global_gem_cache true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem "foo"
end
G
# ensure we also git fetch after cloning
- bundle :update, all: true
+ bundle :update, :all => true
- git("ls-remote .", Dir[home(".bundle/cache/git/foo-*")].first)
+ sys_exec("git ls-remote .", :dir => Dir[home(".bundle/cache/git/foo-*")].first)
expect(out).not_to include("refs/bundler/1")
end
@@ -357,10 +350,10 @@ RSpec.describe "bundle install with git sources" do
let(:repo) { build_git("foo").path }
it "works" do
- update_git("foo", path: repo, branch: branch)
+ update_git("foo", :path => repo, :branch => branch)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :branch => #{branch.dump} do
gem "foo"
end
@@ -374,10 +367,10 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", path: repo, branch: branch)
+ update_git("foo", :path => repo, :branch => branch)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :branch => #{branch.dump} do
gem "foo"
end
@@ -392,10 +385,10 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", path: repo, branch: branch)
+ update_git("foo", :path => repo, :branch => branch)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :branch => #{branch.dump} do
gem "foo"
end
@@ -411,10 +404,10 @@ RSpec.describe "bundle install with git sources" do
let(:repo) { build_git("foo").path }
it "works" do
- update_git("foo", path: repo, tag: tag)
+ update_git("foo", :path => repo, :tag => tag)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :tag => #{tag.dump} do
gem "foo"
end
@@ -428,10 +421,10 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", path: repo, tag: tag)
+ update_git("foo", :path => repo, :tag => tag)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :tag => #{tag.dump} do
gem "foo"
end
@@ -446,10 +439,10 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", path: repo, tag: tag)
+ update_git("foo", :path => repo, :tag => tag)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :tag => #{tag.dump} do
gem "foo"
end
@@ -462,100 +455,100 @@ RSpec.describe "bundle install with git sources" do
describe "when specifying local override" do
it "uses the local repository instead of checking a new one out" do
- build_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
- run "require 'myrack'"
+ run "require 'rack'"
expect(out).to eq("LOCAL")
end
it "chooses the local repository on runtime" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ update_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- run "require 'myrack'"
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ run "require 'rack'"
expect(out).to eq("LOCAL")
end
it "unlocks the source when the dependencies have changed while switching to the local" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "myrack.gemspec", build_spec("myrack", "0.8") { runtime "rspec", "> 0" }.first.to_ruby
- s.write "lib/myrack.rb", "puts :LOCAL"
+ update_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "rack.gemspec", build_spec("rack", "0.8") { runtime "rspec", "> 0" }.first.to_ruby
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
- run "require 'myrack'"
+ run "require 'rack'"
expect(out).to eq("LOCAL")
end
it "updates specs on runtime" do
system_gems "nokogiri-1.4.2"
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
lockfile0 = File.read(bundled_app_lock)
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
+ update_git "rack", "0.8", :path => lib_path("local-rack") do |s|
s.add_dependency "nokogiri", "1.4.2"
end
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- run "require 'myrack'"
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ run "require 'rack'"
lockfile1 = File.read(bundled_app_lock)
expect(lockfile1).not_to eq(lockfile0)
end
it "updates ref on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
lockfile0 = File.read(bundled_app_lock)
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack")
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
+ update_git "rack", "0.8", :path => lib_path("local-rack")
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
lockfile1 = File.read(bundled_app_lock)
@@ -563,18 +556,18 @@ RSpec.describe "bundle install with git sources" do
end
it "explodes and gives correct solution if given path does not exist on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- bundle :install, raise_on_error: false
- expect(err).to match(/Cannot use local override for myrack-0.8 because #{Regexp.escape(lib_path("local-myrack").to_s)} does not exist/)
+ 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/)
- solution = "config unset local.myrack"
+ solution = "config unset local.rack"
expect(err).to match(/Run `bundle #{solution}` to remove the local override/)
bundle solution
@@ -584,19 +577,19 @@ RSpec.describe "bundle install with git sources" do
end
it "explodes and gives correct solution if branch is not given on install" do
- build_git "myrack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ build_git "rack", "0.8"
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- bundle :install, raise_on_error: false
- expect(err).to match(/Cannot use local override for myrack-0.8 at #{Regexp.escape(lib_path("local-myrack").to_s)} because :branch is not specified in Gemfile/)
+ 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/)
- solution = "config unset local.myrack"
+ solution = "config unset local.rack"
expect(err).to match(/Specify a branch or run `bundle #{solution}` to remove the local override/)
bundle solution
@@ -606,69 +599,69 @@ RSpec.describe "bundle install with git sources" do
end
it "does not explode if disable_local_branch_check is given" do
- build_git "myrack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ build_git "rack", "0.8"
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle %(config set disable_local_branch_check true)
bundle :install
expect(out).to match(/Bundle complete!/)
end
it "explodes on different branches on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack"), branch: "another" do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ update_git "rack", "0.8", :path => lib_path("local-rack"), :branch => "another" do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- bundle :install, raise_on_error: false
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ bundle :install, :raise_on_error => false
expect(err).to match(/is using branch another but Gemfile specifies main/)
end
it "explodes on invalid revision on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- build_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- bundle :install, raise_on_error: false
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ bundle :install, :raise_on_error => false
expect(err).to match(/The Gemfile lock is pointing to revision \w+/)
end
it "does not explode on invalid revision on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- build_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle %(config set disable_local_revision_check true)
bundle :install
expect(out).to match(/Bundle complete!/)
@@ -693,76 +686,76 @@ RSpec.describe "bundle install with git sources" do
# end
it "installs from git even if a newer gem is available elsewhere" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}"
G
- expect(the_bundle).to include_gems "myrack 0.8"
+ expect(the_bundle).to include_gems "rack 0.8"
end
it "installs dependencies from git even if a newer gem is available elsewhere" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
- build_lib "myrack", "1.0", path: lib_path("nested/bar") do |s|
- s.write "lib/myrack.rb", "puts 'WIN OVERRIDE'"
+ build_lib "rack", "1.0", :path => lib_path("nested/bar") do |s|
+ s.write "lib/rack.rb", "puts 'WIN OVERRIDE'"
end
- build_git "foo", path: lib_path("nested") do |s|
- s.add_dependency "myrack", "= 1.0"
+ build_git "foo", :path => lib_path("nested") do |s|
+ s.add_dependency "rack", "= 1.0"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("nested")}"
G
- run "require 'myrack'"
+ run "require 'rack'"
expect(out).to eq("WIN OVERRIDE")
end
it "correctly unlocks when changing to a git source" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- build_git "myrack", path: lib_path("myrack")
+ build_git "rack", :path => lib_path("rack")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0", :git => "#{lib_path("myrack")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0", :git => "#{lib_path("rack")}"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "correctly unlocks when changing to a git source without versions" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- build_git "myrack", "1.2", path: lib_path("myrack")
+ build_git "rack", "1.2", :path => lib_path("rack")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack")}"
G
- expect(the_bundle).to include_gems "myrack 1.2"
+ expect(the_bundle).to include_gems "rack 1.2"
end
end
describe "block syntax" do
it "pulls all gems from a git block" do
- build_lib "omg", path: lib_path("hi2u/omg")
- build_lib "hi2u", path: lib_path("hi2u")
+ build_lib "omg", :path => lib_path("hi2u/omg")
+ build_lib "hi2u", :path => lib_path("hi2u")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("hi2u")}" do
gem "omg"
gem "hi2u"
@@ -779,7 +772,7 @@ RSpec.describe "bundle install with git sources" do
update_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "#{@revision}"
G
@@ -797,7 +790,7 @@ RSpec.describe "bundle install with git sources" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
gem "rails", "2.3.2"
G
@@ -807,7 +800,7 @@ RSpec.describe "bundle install with git sources" do
end
it "runs the gemspec in the context of its parent directory" do
- build_lib "bar", path: lib_path("foo/bar"), gemspec: false do |s|
+ build_lib "bar", :path => lib_path("foo/bar"), :gemspec => false do |s|
s.write lib_path("foo/bar/lib/version.rb"), %(BAR_VERSION = '1.0')
s.write "bar.gemspec", <<-G
$:.unshift Dir.pwd
@@ -822,12 +815,12 @@ RSpec.describe "bundle install with git sources" do
G
end
- build_git "foo", path: lib_path("foo") do |s|
+ build_git "foo", :path => lib_path("foo") do |s|
s.write "bin/foo", ""
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("foo")}"
gem "rails", "2.3.2"
G
@@ -836,41 +829,15 @@ RSpec.describe "bundle install with git sources" do
expect(the_bundle).to include_gems "rails 2.3.2"
end
- it "runs the gemspec in the context of its parent directory, when using local overrides" do
- build_git "foo", path: lib_path("foo"), gemspec: false do |s|
- s.write lib_path("foo/lib/foo/version.rb"), %(FOO_VERSION = '1.0')
- s.write "foo.gemspec", <<-G
- $:.unshift Dir.pwd
- require 'lib/foo/version'
- Gem::Specification.new do |s|
- s.name = 'foo'
- s.author = 'no one'
- s.version = FOO_VERSION
- s.summary = 'Foo'
- s.files = Dir["lib/**/*.rb"]
- end
- G
- end
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "https://github.com/gems/foo", branch: "main"
- G
-
- bundle %(config set local.foo #{lib_path("foo")})
-
- expect(the_bundle).to include_gems "foo 1.0"
- end
-
it "installs from git even if a rubygems gem is present" do
- build_gem "foo", "1.0", path: lib_path("fake_foo"), to_system: true do |s|
+ build_gem "foo", "1.0", :path => lib_path("fake_foo"), :to_system => true do |s|
s.write "lib/foo.rb", "raise 'FAIL'"
end
build_git "foo", "1.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :git => "#{lib_path("foo-1.0")}"
G
@@ -878,10 +845,10 @@ RSpec.describe "bundle install with git sources" do
end
it "fakes the gem out if there is no gemspec" do
- build_git "foo", gemspec: false
+ build_git "foo", :gemspec => false
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :git => "#{lib_path("foo-1.0")}"
gem "rails", "2.3.2"
G
@@ -892,11 +859,11 @@ RSpec.describe "bundle install with git sources" do
it "catches git errors and spits out useful output" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :git => "omgomg"
G
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("Git error:")
expect(err).to include("fatal")
@@ -904,10 +871,10 @@ RSpec.describe "bundle install with git sources" do
end
it "works when the gem path has spaces in it" do
- build_git "foo", path: lib_path("foo space-1.0")
+ build_git "foo", :path => lib_path("foo space-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo space-1.0")}"
G
@@ -918,7 +885,7 @@ RSpec.describe "bundle install with git sources" do
build_git "forced", "1.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("forced-1.0")}" do
gem 'forced'
end
@@ -929,12 +896,12 @@ RSpec.describe "bundle install with git sources" do
s.write "lib/forced.rb", "FORCED = '1.1'"
end
- bundle "update", all: true
+ bundle "update", :all => true
expect(the_bundle).to include_gems "forced 1.1"
- git("reset --hard HEAD^", lib_path("forced-1.0"))
+ sys_exec("git reset --hard HEAD^", :dir => lib_path("forced-1.0"))
- bundle "update", all: true
+ bundle "update", :all => true
expect(the_bundle).to include_gems "forced 1.0"
end
@@ -946,16 +913,16 @@ RSpec.describe "bundle install with git sources" do
build_git "has_submodule", "1.0" do |s|
s.add_dependency "submodule"
end
- git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0")
- git "commit -m \"submodulator\"", lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("has_submodule-1.0")}" do
gem "has_submodule"
end
G
- expect(err).to match(%r{submodule >= 0 could not be found in rubygems repository https://gem.repo1/ or installed locally})
+ expect(err).to match(%r{submodule >= 0 could not be found in rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally})
expect(the_bundle).not_to include_gems "has_submodule 1.0"
end
@@ -968,11 +935,11 @@ RSpec.describe "bundle install with git sources" do
build_git "has_submodule", "1.0" do |s|
s.add_dependency "submodule"
end
- git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0")
- git "commit -m \"submodulator\"", lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("has_submodule-1.0")}", :submodules => true do
gem "has_submodule"
end
@@ -988,11 +955,11 @@ RSpec.describe "bundle install with git sources" do
build_git "submodule", "1.0"
build_git "has_submodule", "1.0"
- git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0")
- git "commit -m \"submodulator\"", lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("has_submodule-1.0")}" do
gem "has_submodule"
end
@@ -1007,7 +974,7 @@ RSpec.describe "bundle install with git sources" do
git = build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem "foo"
end
@@ -1017,7 +984,7 @@ RSpec.describe "bundle install with git sources" do
update_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => "#{git.ref_for("HEAD^")}" do
gem "foo"
end
@@ -1035,7 +1002,7 @@ RSpec.describe "bundle install with git sources" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1049,7 +1016,7 @@ RSpec.describe "bundle install with git sources" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1063,8 +1030,8 @@ RSpec.describe "bundle install with git sources" do
FileUtils.mkdir_p(default_bundle_path)
FileUtils.touch(default_bundle_path("bundler"))
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1075,14 +1042,14 @@ RSpec.describe "bundle install with git sources" do
end
it "does not duplicate git gem sources" do
- build_lib "foo", path: lib_path("nested/foo")
- build_lib "bar", path: lib_path("nested/bar")
+ build_lib "foo", :path => lib_path("nested/foo")
+ build_lib "bar", :path => lib_path("nested/bar")
- build_git "foo", path: lib_path("nested")
- build_git "bar", path: lib_path("nested")
+ build_git "foo", :path => lib_path("nested")
+ build_git "bar", :path => lib_path("nested")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("nested")}"
gem "bar", :git => "#{lib_path("nested")}"
G
@@ -1092,21 +1059,21 @@ RSpec.describe "bundle install with git sources" do
describe "switching sources" do
it "doesn't explode when switching Path to Git sources" do
- build_gem "foo", "1.0", to_system: true do |s|
+ build_gem "foo", "1.0", :to_system => true do |s|
s.write "lib/foo.rb", "raise 'fail'"
end
- build_lib "foo", "1.0", path: lib_path("bar/foo")
- build_git "bar", "1.0", path: lib_path("bar") do |s|
+ build_lib "foo", "1.0", :path => lib_path("bar/foo")
+ build_git "bar", "1.0", :path => lib_path("bar") do |s|
s.add_dependency "foo"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :path => "#{lib_path("bar")}"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("bar")}"
G
@@ -1115,43 +1082,24 @@ RSpec.describe "bundle install with git sources" do
it "doesn't explode when switching Gem to Git source" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack-obama"
+ gem "rack", "1.0.0"
G
- build_git "myrack", "1.0" do |s|
+ build_git "rack", "1.0" do |s|
s.write "lib/new_file.rb", "puts 'USING GIT'"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack", "1.0.0", :git => "#{lib_path("myrack-1.0")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack-obama"
+ gem "rack", "1.0.0", :git => "#{lib_path("rack-1.0")}"
G
run "require 'new_file'"
expect(out).to eq("USING GIT")
end
-
- it "doesn't explode when removing an explicit exact version from a git gem with dependencies" do
- build_lib "activesupport", "7.1.4", path: lib_path("rails/activesupport")
- build_git "rails", "7.1.4", path: lib_path("rails") do |s|
- s.add_dependency "activesupport", "= 7.1.4"
- end
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "rails", "7.1.4", :git => "#{lib_path("rails")}"
- G
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "rails", :git => "#{lib_path("rails")}"
- G
-
- expect(the_bundle).to include_gem "rails 7.1.4", "activesupport 7.1.4"
- end
end
describe "bundle install after the remote has been updated" do
@@ -1159,8 +1107,8 @@ RSpec.describe "bundle install with git sources" do
build_git "valim"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "valim", :git => "#{lib_path("valim-1.0")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "valim", :git => "#{file_uri_for(lib_path("valim-1.0"))}"
G
old_revision = revision_for(lib_path("valim-1.0"))
@@ -1185,36 +1133,25 @@ RSpec.describe "bundle install with git sources" do
revision = revision_for(lib_path("foo-1.0"))
install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "#{revision}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :ref => "#{revision}"
G
expect(out).to_not match(/Revision.*does not exist/)
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "deadbeef"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :ref => "deadbeef"
G
expect(err).to include("Revision deadbeef does not exist in the repository")
end
-
- it "gives a helpful error message when the remote branch no longer exists" do
- build_git "foo"
-
- install_gemfile <<-G, env: { "LANG" => "en" }, raise_on_error: false
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "deadbeef"
- G
-
- expect(err).to include("Revision deadbeef does not exist in the repository")
- end
end
describe "bundle install with deployment mode configured and git sources" do
it "works" do
- build_git "valim", path: lib_path("valim")
+ build_git "valim", :path => lib_path("valim")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "valim", "= 1.0", :git => "#{lib_path("valim")}"
G
@@ -1229,7 +1166,7 @@ RSpec.describe "bundle install with git sources" do
it "runs pre-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1242,14 +1179,14 @@ RSpec.describe "bundle install with git sources" do
end
bundle :install,
- requires: [lib_path("install_hooks.rb")]
+ :requires => [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran pre-install hook: foo-1.0")
end
it "runs post-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1262,14 +1199,14 @@ RSpec.describe "bundle install with git sources" do
end
bundle :install,
- requires: [lib_path("install_hooks.rb")]
+ :requires => [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran post-install hook: foo-1.0")
end
it "complains if the install hook fails" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1281,7 +1218,7 @@ RSpec.describe "bundle install with git sources" do
H
end
- bundle :install, requires: [lib_path("install_hooks.rb")], raise_on_error: false
+ bundle :install, :requires => [lib_path("install_hooks.rb")], :raise_on_error => false
expect(err).to include("failed for foo-1.0")
end
end
@@ -1303,7 +1240,7 @@ RSpec.describe "bundle install with git sources" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1320,10 +1257,11 @@ RSpec.describe "bundle install with git sources" do
end
it "does not use old extension after ref changes" do
- git_reader = build_git "foo", no_default: true do |s|
+ git_reader = build_git "foo", :no_default => true do |s|
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-RUBY
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
create_makefile("foo")
RUBY
s.write "ext/foo.c", "void Init_foo() {}"
@@ -1337,12 +1275,12 @@ RSpec.describe "bundle install with git sources" do
void Init_foo() { rb_define_global_function("foo", &foo, 0); }
C
end
- git("commit -m \"commit for iteration #{i}\" ext/foo.c", git_reader.path)
+ sys_exec("git commit -m \"commit for iteration #{i}\" ext/foo.c", :dir => git_reader.path)
git_commit_sha = git_reader.ref_for("HEAD")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "#{git_commit_sha}"
G
@@ -1366,8 +1304,8 @@ RSpec.describe "bundle install with git sources" do
RUBY
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1397,7 +1335,7 @@ In Gemfile:
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1410,7 +1348,7 @@ In Gemfile:
expect(installed_time).to match(/\A\d+\.\d+\z/)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1438,8 +1376,8 @@ In Gemfile:
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1452,8 +1390,8 @@ In Gemfile:
expect(installed_time).to match(/\A\d+\.\d+\z/)
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1481,7 +1419,7 @@ In Gemfile:
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1492,12 +1430,12 @@ In Gemfile:
installed_time = out
- update_git("foo", branch: "branch2")
+ update_git("foo", :branch => "branch2")
expect(installed_time).to match(/\A\d+\.\d+\z/)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "branch2"
G
@@ -1530,7 +1468,7 @@ In Gemfile:
ENV["GIT_WORK_TREE"] = "bar"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("xxxxxx-1.0")}" do
gem 'xxxxxx'
end
@@ -1544,7 +1482,7 @@ In Gemfile:
describe "without git installed" do
it "prints a better error message when installing" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake", git: "https://github.com/ruby/rake"
G
@@ -1571,7 +1509,7 @@ In Gemfile:
L
with_path_as("") do
- bundle "install", raise_on_error: false
+ bundle "install", :raise_on_error => false
end
expect(err).
to include("You need to install git to be able to use gems from git repositories. For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git")
@@ -1581,33 +1519,33 @@ In Gemfile:
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
G
with_path_as("") do
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
end
expect(err).
to include("You need to install git to be able to use gems from git repositories. For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git")
end
- it "doesn't need git in the new machine if an installed git gem is copied to another machine" do
+ it "installs a packaged git gem successfully" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
G
- bundle "config set --global path vendor/bundle"
- bundle :install
+ bundle "config set cache_all true"
+ bundle :cache
simulate_new_machine
- bundle "install", env: { "PATH" => "" }
+ bundle "install", :env => { "PATH" => "" }
expect(out).to_not include("You need to install git to be able to use gems from git repositories.")
end
end
@@ -1625,10 +1563,10 @@ In Gemfile:
end
it "installs successfully" do
- build_git "foo", "1.0", path: lib_path("foo")
+ build_git "foo", "1.0", :path => lib_path("foo")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo")}", :branch => "main"
G
@@ -1643,8 +1581,8 @@ In Gemfile:
let(:credentials) { "user1:password1" }
it "does not display the password" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
git "https://#{credentials}@github.com/company/private-repo" do
gem "foo"
end
@@ -1659,8 +1597,8 @@ In Gemfile:
let(:credentials) { "oauth_token" }
it "displays the oauth scheme but not the oauth token" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
git "https://#{credentials}:x-oauth-basic@github.com/company/private-repo" do
gem "foo"
end
diff --git a/spec/bundler/install/gemfile/groups_spec.rb b/spec/bundler/install/gemfile/groups_spec.rb
index 71871899a2..734e012e84 100644
--- a/spec/bundler/install/gemfile/groups_spec.rb
+++ b/spec/bundler/install/gemfile/groups_spec.rb
@@ -4,8 +4,8 @@ RSpec.describe "bundle install with groups" do
describe "installing with no options" do
before :each do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo do
gem "activesupport", "2.3.5"
end
@@ -14,7 +14,7 @@ RSpec.describe "bundle install with groups" do
end
it "installs gems in the default group" do
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs gems in a group block into that group" do
@@ -40,7 +40,7 @@ RSpec.describe "bundle install with groups" do
end
it "sets up everything if Bundler.setup is used with no groups" do
- output = run("require 'myrack'; puts MYRACK")
+ output = run("require 'rack'; puts RACK")
expect(output).to eq("1.0.0")
output = run("require 'activesupport'; puts ACTIVESUPPORT")
@@ -74,8 +74,8 @@ RSpec.describe "bundle install with groups" do
describe "with gems assigned to a single group" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo do
gem "activesupport", "2.3.5"
end
@@ -88,32 +88,32 @@ RSpec.describe "bundle install with groups" do
it "installs gems in the default group" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0", groups: [:default]
+ expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default]
end
it "respects global `without` configuration, but does not save it locally" do
bundle "config set --global without emo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0", groups: [:default]
+ expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default]
bundle "config list"
expect(out).not_to include("Set for your local app (#{bundled_app(".bundle/config")}): [:emo]")
expect(out).to include("Set for the current user (#{home(".bundle/config")}): [:emo]")
end
- it "allows running application where groups where configured by a different user", bundler: "< 3" do
+ it "allows running application where groups where configured by a different user", :bundler => "< 3" do
bundle "config set without emo"
bundle :install
- bundle "exec ruby -e 'puts 42'", env: { "BUNDLE_USER_HOME" => tmp("new_home").to_s }
+ bundle "exec ruby -e 'puts 42'", :env => { "BUNDLE_USER_HOME" => tmp("new_home").to_s }
expect(out).to include("42")
end
it "does not install gems from the excluded group" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).not_to include_gems "activesupport 2.3.5", groups: [:default]
+ expect(the_bundle).not_to include_gems "activesupport 2.3.5", :groups => [:default]
end
- it "remembers previous exclusion with `--without`", bundler: "< 3" do
+ it "remembers previous exclusion with `--without`", :bundler => "< 3" do
bundle "install --without emo"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
bundle :install
@@ -129,13 +129,13 @@ RSpec.describe "bundle install with groups" do
it "allows Bundler.setup for specific groups" do
bundle "config set --local without emo"
bundle :install
- run("require 'myrack'; puts MYRACK", :default)
+ run("require 'rack'; puts RACK", :default)
expect(out).to eq("1.0.0")
end
it "does not effect the resolve" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
group :emo do
gem "rails", "2.3.2"
@@ -144,7 +144,7 @@ RSpec.describe "bundle install with groups" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "activesupport 2.3.2", groups: [:default]
+ expect(the_bundle).to include_gems "activesupport 2.3.2", :groups => [:default]
end
it "still works when BUNDLE_WITHOUT is set" do
@@ -153,20 +153,20 @@ RSpec.describe "bundle install with groups" do
bundle :install
expect(out).not_to include("activesupport")
- expect(the_bundle).to include_gems "myrack 1.0.0", groups: [:default]
- expect(the_bundle).not_to include_gems "activesupport 2.3.5", groups: [:default]
+ expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default]
+ expect(the_bundle).not_to include_gems "activesupport 2.3.5", :groups => [:default]
ENV["BUNDLE_WITHOUT"] = nil
end
- it "clears --without when passed an empty list", bundler: "< 3" do
+ it "clears --without when passed an empty list", :bundler => "< 3" do
bundle "install --without emo"
bundle "install --without ''"
expect(the_bundle).to include_gems "activesupport 2.3.5"
end
- it "doesn't clear without when nothing is passed", bundler: "< 3" do
+ it "doesn't clear without when nothing is passed", :bundler => "< 3" do
bundle "install --without emo"
bundle :install
@@ -184,7 +184,7 @@ RSpec.describe "bundle install with groups" do
expect(the_bundle).to include_gems "thin 1.0"
end
- it "installs gems from the previously requested group", bundler: "< 3" do
+ it "installs gems from the previously requested group", :bundler => "< 3" do
bundle "install --with debugging"
expect(the_bundle).to include_gems "thin 1.0"
bundle :install
@@ -198,26 +198,26 @@ RSpec.describe "bundle install with groups" do
ENV["BUNDLE_WITH"] = nil
end
- it "clears --with when passed an empty list", bundler: "< 3" do
+ it "clears --with when passed an empty list", :bundler => "< 3" do
bundle "install --with debugging"
bundle "install --with ''"
expect(the_bundle).not_to include_gems "thin 1.0"
end
- it "removes groups from without when passed at --with", bundler: "< 3" do
+ it "removes groups from without when passed at --with", :bundler => "< 3" do
bundle "config set --local without emo"
bundle "install --with emo"
expect(the_bundle).to include_gems "activesupport 2.3.5"
end
- it "removes groups from with when passed at --without", bundler: "< 3" do
+ it "removes groups from with when passed at --without", :bundler => "< 3" do
bundle "config set --local with debugging"
- bundle "install --without debugging", raise_on_error: false
+ bundle "install --without debugging", :raise_on_error => false
expect(the_bundle).not_to include_gem "thin 1.0"
end
- it "errors out when passing a group to with and without via CLI flags", bundler: "< 3" do
- bundle "install --with emo debugging --without emo", raise_on_error: false
+ it "errors out when passing a group to with and without via CLI flags", :bundler => "< 3" do
+ bundle "install --with emo debugging --without emo", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("The offending groups are: emo")
end
@@ -235,7 +235,7 @@ RSpec.describe "bundle install with groups" do
expect(the_bundle).to include_gem "thin 1.0"
end
- it "can add and remove a group at the same time", bundler: "< 3" do
+ it "can add and remove a group at the same time", :bundler => "< 3" do
bundle "install --with debugging --without emo"
expect(the_bundle).to include_gems "thin 1.0"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
@@ -257,8 +257,8 @@ RSpec.describe "bundle install with groups" do
describe "with gems assigned to multiple groups" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo, :lolercoaster do
gem "activesupport", "2.3.5"
end
@@ -268,20 +268,20 @@ RSpec.describe "bundle install with groups" do
it "installs gems in the default group" do
bundle "config set --local without emo lolercoaster"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs the gem if any of its groups are installed" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5"
end
describe "with a gem defined multiple times in different groups" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo do
gem "activesupport", "2.3.5"
@@ -316,8 +316,8 @@ RSpec.describe "bundle install with groups" do
describe "nesting groups" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo do
group :lolercoaster do
gem "activesupport", "2.3.5"
@@ -329,13 +329,13 @@ RSpec.describe "bundle install with groups" do
it "installs gems in the default group" do
bundle "config set --local without emo lolercoaster"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs the gem if any of its groups are installed" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5"
end
end
end
@@ -343,16 +343,16 @@ RSpec.describe "bundle install with groups" do
describe "when loading only the default group" do
it "should not load all groups" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :groups => :development
G
ruby <<-R
- require "bundler"
+ require "#{entrypoint}"
Bundler.setup :default
Bundler.require :default
- puts MYRACK
+ puts RACK
begin
require "activesupport"
rescue LoadError
@@ -369,34 +369,34 @@ RSpec.describe "bundle install with groups" do
before(:each) do
build_repo2
- system_gems "myrack-0.9.1"
+ system_gems "rack-0.9.1"
- bundle "config set --local without myrack"
+ bundle "config set --local without rack"
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
- group :myrack do
- gem "myrack_middleware"
+ group :rack do
+ gem "rack_middleware"
end
G
end
it "uses the correct versions even if --without was used on the original" do
- expect(the_bundle).to include_gems "myrack 0.9.1"
- expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
+ expect(the_bundle).to include_gems "rack 0.9.1"
+ expect(the_bundle).not_to include_gems "rack_middleware 1.0"
simulate_new_machine
bundle :install
- expect(the_bundle).to include_gems "myrack 0.9.1"
- expect(the_bundle).to include_gems "myrack_middleware 1.0"
+ expect(the_bundle).to include_gems "rack 0.9.1"
+ expect(the_bundle).to include_gems "rack_middleware 1.0"
end
it "does not hit the remote a second time" do
FileUtils.rm_rf gem_repo2
- bundle "config set --local without myrack"
- bundle :install, verbose: true
+ bundle "config set --local without rack"
+ bundle :install, :verbose => true
expect(last_command.stdboth).not_to match(/fetching/i)
end
end
diff --git a/spec/bundler/install/gemfile/install_if_spec.rb b/spec/bundler/install/gemfile/install_if_spec.rb
index 170b58c4c0..3d2d15a698 100644
--- a/spec/bundler/install/gemfile/install_if_spec.rb
+++ b/spec/bundler/install/gemfile/install_if_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle install with install_if conditionals" do
it "follows the install_if DSL" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
install_if(lambda { true }) do
gem "activesupport", "2.3.5"
end
@@ -11,29 +11,22 @@ RSpec.describe "bundle install with install_if conditionals" do
install_if(lambda { false }) do
gem "foo"
end
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems("myrack 1.0", "activesupport 2.3.5")
+ expect(the_bundle).to include_gems("rack 1.0", "activesupport 2.3.5")
expect(the_bundle).not_to include_gems("thin")
expect(the_bundle).not_to include_gems("foo")
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "activesupport", "2.3.5"
- c.checksum gem_repo1, "foo", "1.0"
- c.checksum gem_repo1, "myrack", "1.0.0"
- c.checksum gem_repo1, "thin", "1.0"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
activesupport (2.3.5)
foo (1.0)
- myrack (1.0.0)
+ rack (1.0.0)
thin (1.0)
- myrack
+ rack
PLATFORMS
#{lockfile_platforms}
@@ -41,9 +34,9 @@ RSpec.describe "bundle install with install_if conditionals" do
DEPENDENCIES
activesupport (= 2.3.5)
foo
- myrack
+ rack
thin
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/install/gemfile/lockfile_spec.rb b/spec/bundler/install/gemfile/lockfile_spec.rb
index f80b21e562..313e99d0b8 100644
--- a/spec/bundler/install/gemfile/lockfile_spec.rb
+++ b/spec/bundler/install/gemfile/lockfile_spec.rb
@@ -2,20 +2,15 @@
RSpec.describe "bundle install with a lockfile present" do
let(:gf) { <<-G }
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
subject do
install_gemfile(gf)
end
- it "touches the lockfile on install even when nothing has changed" do
- subject
- expect { bundle :install }.to change { bundled_app_lock.mtime }
- end
-
context "gemfile evaluation" do
let(:gf) { super() + "\n\n File.open('evals', 'a') {|f| f << %(1\n) } unless ENV['BUNDLER_SPEC_NO_APPEND']" }
@@ -28,7 +23,7 @@ RSpec.describe "bundle install with a lockfile present" do
it "does not evaluate the gemfile twice" do
bundle :install
- with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "myrack 1.0.0" }
+ with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "rack 1.0.0" }
# The first eval is from the initial install, we're testing that the
# second install doesn't double-eval
@@ -41,7 +36,7 @@ RSpec.describe "bundle install with a lockfile present" do
it "does not evaluate the gemfile twice" do
bundle :install
- with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "myrack 1.0.0" }
+ with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "rack 1.0.0" }
# The first eval is from the initial install, we're testing that the
# second install doesn't double-eval
diff --git a/spec/bundler/install/gemfile/path_spec.rb b/spec/bundler/install/gemfile/path_spec.rb
index 7525404b24..9ef1c879f8 100644
--- a/spec/bundler/install/gemfile/path_spec.rb
+++ b/spec/bundler/install/gemfile/path_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe "bundle install with explicit source paths" do
- it "fetches gems with a global path source", bundler: "< 3" do
+ it "fetches gems with a global path source", :bundler => "< 3" do
build_lib "foo"
install_gemfile <<-G
@@ -16,7 +16,7 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -29,7 +29,7 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "#{lib_path("foo-1.0")}"
G
@@ -42,7 +42,7 @@ RSpec.describe "bundle install with explicit source paths" do
relative_path = lib_path("foo-1.0").relative_path_from(bundled_app)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "#{relative_path}"
G
@@ -55,7 +55,7 @@ RSpec.describe "bundle install with explicit source paths" do
relative_path = lib_path("foo-1.0").relative_path_from(Pathname.new("~").expand_path)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "~/#{relative_path}"
G
@@ -69,8 +69,8 @@ RSpec.describe "bundle install with explicit source paths" do
username = "some_unexisting_user"
relative_path = lib_path("foo-1.0").relative_path_from(Pathname.new("/home/#{username}").expand_path)
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "~#{username}/#{relative_path}"
G
expect(err).to match("There was an error while trying to use the path `~#{username}/#{relative_path}`.")
@@ -78,31 +78,26 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "expands paths relative to Bundler.root" do
- build_lib "foo", path: bundled_app("foo-1.0")
+ build_lib "foo", :path => bundled_app("foo-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "./foo-1.0"
G
- expect(the_bundle).to include_gems("foo 1.0", dir: bundled_app("subdir").mkpath)
+ expect(the_bundle).to include_gems("foo 1.0", :dir => bundled_app("subdir").mkpath)
end
it "sorts paths consistently on install and update when they start with ./" do
- build_lib "demo", path: lib_path("demo")
- build_lib "aaa", path: lib_path("demo/aaa")
+ build_lib "demo", :path => lib_path("demo")
+ build_lib "aaa", :path => lib_path("demo/aaa")
gemfile lib_path("demo/Gemfile"), <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
gem "aaa", :path => "./aaa"
G
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "aaa", "1.0"
- c.no_checksum "demo", "1.0"
- end
-
lockfile = <<~L
PATH
remote: .
@@ -115,7 +110,7 @@ RSpec.describe "bundle install with explicit source paths" do
aaa (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -124,22 +119,22 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
aaa!
demo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
- bundle :install, dir: lib_path("demo")
+ bundle :install, :dir => lib_path("demo")
expect(lib_path("demo/Gemfile.lock")).to read_as(lockfile)
- bundle :update, all: true, dir: lib_path("demo")
+ bundle :update, :all => true, :dir => lib_path("demo")
expect(lib_path("demo/Gemfile.lock")).to read_as(lockfile)
end
it "expands paths when comparing locked paths to Gemfile paths" do
- build_lib "foo", path: bundled_app("foo-1.0")
+ build_lib "foo", :path => bundled_app("foo-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => File.expand_path("foo-1.0", __dir__)
G
@@ -148,38 +143,38 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "installs dependencies from the path even if a newer gem is available elsewhere" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
- build_lib "myrack", "1.0", path: lib_path("nested/bar") do |s|
- s.write "lib/myrack.rb", "puts 'WIN OVERRIDE'"
+ build_lib "rack", "1.0", :path => lib_path("nested/bar") do |s|
+ s.write "lib/rack.rb", "puts 'WIN OVERRIDE'"
end
- build_lib "foo", path: lib_path("nested") do |s|
- s.add_dependency "myrack", "= 1.0"
+ build_lib "foo", :path => lib_path("nested") do |s|
+ s.add_dependency "rack", "= 1.0"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("nested")}"
G
- run "require 'myrack'"
+ run "require 'rack'"
expect(out).to eq("WIN OVERRIDE")
end
it "works" do
- build_gem "foo", "1.0.0", to_system: true do |s|
+ build_gem "foo", "1.0.0", :to_system => true do |s|
s.write "lib/foo.rb", "puts 'FAIL'"
end
- build_lib "omg", "1.0", path: lib_path("omg") do |s|
+ build_lib "omg", "1.0", :path => lib_path("omg") do |s|
s.add_dependency "foo"
end
- build_lib "foo", "1.0.0", path: lib_path("omg/foo")
+ build_lib "foo", "1.0.0", :path => lib_path("omg/foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "omg", :path => "#{lib_path("omg")}"
G
@@ -187,10 +182,10 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "works when using prereleases of 0.0.0" do
- build_lib "foo", "0.0.0.dev", path: lib_path("foo")
+ build_lib "foo", "0.0.0.dev", :path => lib_path("foo")
gemfile <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
@@ -201,7 +196,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo (0.0.0.dev)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -220,10 +215,10 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "works when using uppercase prereleases of 0.0.0" do
- build_lib "foo", "0.0.0.SNAPSHOT", path: lib_path("foo")
+ build_lib "foo", "0.0.0.SNAPSHOT", :path => lib_path("foo")
gemfile <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
@@ -234,7 +229,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo (0.0.0.SNAPSHOT)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -253,14 +248,14 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "handles downgrades" do
- build_lib "omg", "2.0", path: lib_path("omg")
+ build_lib "omg", "2.0", :path => lib_path("omg")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "omg", :path => "#{lib_path("omg")}"
G
- build_lib "omg", "1.0", path: lib_path("omg")
+ build_lib "omg", "1.0", :path => lib_path("omg")
bundle :install
@@ -268,7 +263,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "prefers gemspecs closer to the path root" do
- build_lib "premailer", "1.0.0", path: lib_path("premailer") do |s|
+ build_lib "premailer", "1.0.0", :path => lib_path("premailer") do |s|
s.write "gemfiles/ruby187.gemspec", <<-G
Gem::Specification.new do |s|
s.name = 'premailer'
@@ -280,7 +275,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "premailer", :path => "#{lib_path("premailer")}"
G
@@ -301,8 +296,8 @@ RSpec.describe "bundle install with explicit source paths" do
G
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
@@ -313,18 +308,18 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "supports gemspec syntax" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
end
gemfile lib_path("foo/Gemfile"), <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
- bundle "install", dir: lib_path("foo")
- expect(the_bundle).to include_gems "foo 1.0", dir: lib_path("foo")
- expect(the_bundle).to include_gems "myrack 1.0", dir: lib_path("foo")
+ bundle "install", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo")
end
it "does not unlock dependencies of path sources" do
@@ -333,24 +328,19 @@ RSpec.describe "bundle install with explicit source paths" do
build_gem "graphql", "2.0.16"
end
- build_lib "foo", "0.1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "0.1.0", :path => lib_path("foo") do |s|
s.add_dependency "graphql", "~> 2.0"
end
gemfile_path = lib_path("foo/Gemfile")
gemfile gemfile_path, <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gemspec
G
lockfile_path = lib_path("foo/Gemfile.lock")
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "0.1.0"
- c.checksum gem_repo4, "graphql", "2.0.15"
- end
-
original_lockfile = <<~L
PATH
remote: .
@@ -359,7 +349,7 @@ RSpec.describe "bundle install with explicit source paths" do
graphql (~> 2.0)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
graphql (2.0.15)
@@ -368,79 +358,79 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
lockfile lockfile_path, original_lockfile
- build_lib "foo", "0.1.1", path: lib_path("foo") do |s|
+ build_lib "foo", "0.1.1", :path => lib_path("foo") do |s|
s.add_dependency "graphql", "~> 2.0"
end
- bundle "install", dir: lib_path("foo")
+ bundle "install", :dir => lib_path("foo")
expect(lockfile_path).to read_as(original_lockfile.gsub("foo (0.1.0)", "foo (0.1.1)"))
end
it "supports gemspec syntax with an alternative path" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("foo")}"
G
expect(the_bundle).to include_gems "foo 1.0"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
it "doesn't automatically unlock dependencies when using the gemspec syntax" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", ">= 1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", ">= 1.0"
end
- install_gemfile lib_path("foo/Gemfile"), <<-G, dir: lib_path("foo")
- source "https://gem.repo1"
+ install_gemfile lib_path("foo/Gemfile"), <<-G, :dir => lib_path("foo")
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
- build_gem "myrack", "1.0.1", to_system: true
+ build_gem "rack", "1.0.1", :to_system => true
- bundle "install", dir: lib_path("foo")
+ bundle "install", :dir => lib_path("foo")
- expect(the_bundle).to include_gems "foo 1.0", dir: lib_path("foo")
- expect(the_bundle).to include_gems "myrack 1.0", dir: lib_path("foo")
+ expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo")
end
it "doesn't automatically unlock dependencies when using the gemspec syntax and the gem has development dependencies" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", ">= 1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", ">= 1.0"
s.add_development_dependency "activesupport"
end
- install_gemfile lib_path("foo/Gemfile"), <<-G, dir: lib_path("foo")
- source "https://gem.repo1"
+ install_gemfile lib_path("foo/Gemfile"), <<-G, :dir => lib_path("foo")
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
- build_gem "myrack", "1.0.1", to_system: true
+ build_gem "rack", "1.0.1", :to_system => true
- bundle "install", dir: lib_path("foo")
+ bundle "install", :dir => lib_path("foo")
- expect(the_bundle).to include_gems "foo 1.0", dir: lib_path("foo")
- expect(the_bundle).to include_gems "myrack 1.0", dir: lib_path("foo")
+ expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo")
end
it "raises if there are multiple gemspecs" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.write "bar.gemspec", build_spec("bar", "1.0").first.to_ruby
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("foo")}"
G
@@ -449,12 +439,12 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "allows :name to be specified to resolve ambiguity" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.write "bar.gemspec"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("foo")}", :name => "foo"
G
@@ -466,8 +456,8 @@ RSpec.describe "bundle install with explicit source paths" do
s.executables = "foobar"
end
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -485,7 +475,7 @@ RSpec.describe "bundle install with explicit source paths" do
lib_path("foo-1.0").join("bin/performance").mkpath
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', '1.0', :path => "#{lib_path("foo-1.0")}"
G
expect(err).to be_empty
@@ -495,7 +485,7 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "#{lib_path("foo-1.0")}"
G
@@ -508,7 +498,7 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "hi2u"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "omg"
gem "hi2u"
@@ -520,14 +510,14 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "keeps source pinning" do
- build_lib "foo", "1.0", path: lib_path("foo")
- build_lib "omg", "1.0", path: lib_path("omg")
- build_lib "foo", "1.0", path: lib_path("omg/foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo")
+ build_lib "omg", "1.0", :path => lib_path("omg")
+ build_lib "foo", "1.0", :path => lib_path("omg/foo") do |s|
s.write "lib/foo.rb", "puts 'FAIL'"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
gem "omg", :path => "#{lib_path("omg")}"
G
@@ -536,10 +526,10 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "works when the path does not have a gemspec" do
- build_lib "foo", gemspec: false
+ build_lib "foo", :gemspec => false
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :path => "#{lib_path("foo-1.0")}"
G
@@ -569,34 +559,34 @@ RSpec.describe "bundle install with explicit source paths" do
context "existing lockfile" do
it "rubygems gems don't re-resolve without changes" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack-obama', '1.0'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack-obama', '1.0'
gem 'net-ssh', '1.0'
G
- bundle :check, env: { "DEBUG" => "1" }
+ bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
- expect(the_bundle).to include_gems "myrack-obama 1.0", "net-ssh 1.0"
+ expect(the_bundle).to include_gems "rack-obama 1.0", "net-ssh 1.0"
end
it "source path gems w/deps don't re-resolve without changes" do
- build_lib "myrack-obama", "1.0", path: lib_path("omg") do |s|
+ build_lib "rack-obama", "1.0", :path => lib_path("omg") do |s|
s.add_dependency "yard"
end
- build_lib "net-ssh", "1.0", path: lib_path("omg") do |s|
+ build_lib "net-ssh", "1.0", :path => lib_path("omg") do |s|
s.add_dependency "yard"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack-obama', :path => "#{lib_path("omg")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack-obama', :path => "#{lib_path("omg")}"
gem 'net-ssh', :path => "#{lib_path("omg")}"
G
- bundle :check, env: { "DEBUG" => "1" }
+ bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
- expect(the_bundle).to include_gems "myrack-obama 1.0", "net-ssh 1.0"
+ expect(the_bundle).to include_gems "rack-obama 1.0", "net-ssh 1.0"
end
end
@@ -606,7 +596,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
@@ -616,19 +606,19 @@ RSpec.describe "bundle install with explicit source paths" do
describe "when the gem version in the path is updated" do
before :each do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.add_dependency "bar"
end
- build_lib "bar", "1.0", path: lib_path("foo/bar")
+ build_lib "bar", "1.0", :path => lib_path("foo/bar")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
end
it "unlocks all gems when the top level gem is updated" do
- build_lib "foo", "2.0", path: lib_path("foo") do |s|
+ build_lib "foo", "2.0", :path => lib_path("foo") do |s|
s.add_dependency "bar"
end
@@ -638,7 +628,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "unlocks all gems when a child dependency gem is updated" do
- build_lib "bar", "2.0", path: lib_path("foo/bar")
+ build_lib "bar", "2.0", :path => lib_path("foo/bar")
bundle "install"
@@ -648,62 +638,57 @@ RSpec.describe "bundle install with explicit source paths" do
describe "when dependencies in the path are updated" do
before :each do
- build_lib "foo", "1.0", path: lib_path("foo")
+ build_lib "foo", "1.0", :path => lib_path("foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
end
it "gets dependencies that are updated in the path" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack"
end
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "keeps using the same version if it's compatible" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "0.9.1"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "0.9.1"
end
bundle "install"
- expect(the_bundle).to include_gems "myrack 0.9.1"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo1, "myrack", "0.9.1"
- end
+ expect(the_bundle).to include_gems "rack 0.9.1"
expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack (= 0.9.1)
+ rack (= 0.9.1)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack"
end
bundle "install"
@@ -713,168 +698,109 @@ RSpec.describe "bundle install with explicit source paths" do
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack
+ rack
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
- expect(the_bundle).to include_gems "myrack 0.9.1"
+ expect(the_bundle).to include_gems "rack 0.9.1"
end
it "keeps using the same version even when another dependency is added" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "0.9.1"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "0.9.1"
end
bundle "install"
- expect(the_bundle).to include_gems "myrack 0.9.1"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo1, "myrack", "0.9.1"
- end
+ expect(the_bundle).to include_gems "rack 0.9.1"
expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack (= 0.9.1)
+ rack (= 0.9.1)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack"
- s.add_dependency "rake", rake_version
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack"
+ s.add_dependency "rake", "13.0.1"
end
bundle "install"
- checksums.checksum gem_repo1, "rake", rake_version
-
expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack
- rake (= #{rake_version})
+ rack
+ rake (= 13.0.1)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
- rake (#{rake_version})
+ rack (0.9.1)
+ rake (13.0.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- G
- expect(the_bundle).to include_gems "myrack 0.9.1"
- end
-
- it "does not remove existing ruby platform" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "0.9.1"
- end
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
-
- lockfile <<~L
- PATH
- remote: #{lib_path("foo")}
- specs:
- foo (1.0)
-
- PLATFORMS
- #{lockfile_platforms("ruby")}
-
- DEPENDENCIES
- foo!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock"
-
- checksums.checksum gem_repo1, "myrack", "0.9.1"
-
- expect(lockfile).to eq <<~G
- PATH
- remote: #{lib_path("foo")}
- specs:
- foo (1.0)
- myrack (= 0.9.1)
-
- GEM
- remote: https://gem.repo1/
- specs:
- myrack (0.9.1)
-
- PLATFORMS
- #{lockfile_platforms("ruby")}
-
- DEPENDENCIES
- foo!
- #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
+
+ expect(the_bundle).to include_gems "rack 0.9.1"
end
end
describe "switching sources" do
it "doesn't switch pinned git sources to rubygems when pinning the parent gem to a path source" do
- build_gem "foo", "1.0", to_system: true do |s|
+ build_gem "foo", "1.0", :to_system => true do |s|
s.write "lib/foo.rb", "raise 'fail'"
end
- build_lib "foo", "1.0", path: lib_path("bar/foo")
- build_git "bar", "1.0", path: lib_path("bar") do |s|
+ build_lib "foo", "1.0", :path => lib_path("bar/foo")
+ build_git "bar", "1.0", :path => lib_path("bar") do |s|
s.add_dependency "foo"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("bar")}"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :path => "#{lib_path("bar")}"
G
@@ -882,23 +808,23 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "switches the source when the gem existed in rubygems and the path was already being used for another gem" do
- build_lib "foo", "1.0", path: lib_path("foo")
- build_gem "bar", "1.0", to_bundle: true do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo")
+ build_gem "bar", "1.0", :to_bundle => true do |s|
s.write "lib/bar.rb", "raise 'fail'"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar"
path "#{lib_path("foo")}" do
gem "foo"
end
G
- build_lib "bar", "1.0", path: lib_path("foo/bar")
+ build_lib "bar", "1.0", :path => lib_path("foo/bar")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("foo")}" do
gem "foo"
gem "bar"
@@ -911,17 +837,17 @@ RSpec.describe "bundle install with explicit source paths" do
describe "when there are both a gemspec and remote gems" do
it "doesn't query rubygems for local gemspec name" do
- build_lib "private_lib", "2.2", path: lib_path("private_lib")
+ build_lib "private_lib", "2.2", :path => lib_path("private_lib")
gemfile lib_path("private_lib/Gemfile"), <<-G
source "http://localgemserver.test"
gemspec
- gem 'myrack'
+ gem 'rack'
G
- bundle :install, env: { "DEBUG" => "1" }, artifice: "endpoint", dir: lib_path("private_lib")
- expect(out).to match(%r{^HTTP GET http://localgemserver\.test/api/v1/dependencies\?gems=myrack$})
+ bundle :install, :env => { "DEBUG" => "1" }, :artifice => "endpoint", :dir => lib_path("private_lib")
+ expect(out).to match(%r{^HTTP GET http://localgemserver\.test/api/v1/dependencies\?gems=rack$})
expect(out).not_to match(/^HTTP GET.*private_lib/)
- expect(the_bundle).to include_gems "private_lib 2.2", dir: lib_path("private_lib")
- expect(the_bundle).to include_gems "myrack 1.0", dir: lib_path("private_lib")
+ expect(the_bundle).to include_gems "private_lib 2.2", :dir => lib_path("private_lib")
+ expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("private_lib")
end
end
@@ -929,7 +855,7 @@ RSpec.describe "bundle install with explicit source paths" do
it "runs pre-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -942,14 +868,14 @@ RSpec.describe "bundle install with explicit source paths" do
end
bundle :install,
- requires: [lib_path("install_hooks.rb")]
+ :requires => [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran pre-install hook: foo-1.0")
end
it "runs post-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -962,14 +888,14 @@ RSpec.describe "bundle install with explicit source paths" do
end
bundle :install,
- requires: [lib_path("install_hooks.rb")]
+ :requires => [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran post-install hook: foo-1.0")
end
it "complains if the install hook fails" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -981,7 +907,7 @@ RSpec.describe "bundle install with explicit source paths" do
H
end
- bundle :install, requires: [lib_path("install_hooks.rb")], raise_on_error: false
+ bundle :install, :requires => [lib_path("install_hooks.rb")], :raise_on_error => false
expect(err).to include("failed for foo-1.0")
end
@@ -1000,7 +926,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
gem "bar", :path => "#{lib_path("bar-1.0")}"
G
diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb
index 820feb18bf..e9cf0cb636 100644
--- a/spec/bundler/install/gemfile/platform_spec.rb
+++ b/spec/bundler/install/gemfile/platform_spec.rb
@@ -4,30 +4,30 @@ RSpec.describe "bundle install across platforms" do
it "maintains the same lockfile if all gems are compatible across platforms" do
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{not_local}
DEPENDENCIES
- myrack
+ rack
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 0.9.1"
+ expect(the_bundle).to include_gems "rack 0.9.1"
end
it "pulls in the correct platform specific gem" do
lockfile <<-G
GEM
- remote: https://gem.repo1
+ remote: #{file_uri_for(gem_repo1)}
specs:
platform_specific (1.0)
platform_specific (1.0-java)
@@ -40,21 +40,20 @@ RSpec.describe "bundle install across platforms" do
platform_specific
G
- simulate_platform "java" do
- install_gemfile <<-G
- source "https://gem.repo1"
+ simulate_platform "java"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
- gem "platform_specific"
- G
+ gem "platform_specific"
+ G
- expect(the_bundle).to include_gems "platform_specific 1.0 java"
- end
+ expect(the_bundle).to include_gems "platform_specific 1.0 JAVA"
end
it "pulls the pure ruby version on jruby if the java platform is not present in the lockfile and bundler is run in frozen mode", :jruby_only do
lockfile <<-G
GEM
- remote: https://gem.repo1
+ remote: #{file_uri_for(gem_repo1)}
specs:
platform_specific (1.0)
@@ -68,12 +67,12 @@ RSpec.describe "bundle install across platforms" do
bundle "config set --local frozen true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
end
context "on universal Rubies" do
@@ -81,12 +80,15 @@ RSpec.describe "bundle install across platforms" do
build_repo4 do
build_gem "darwin_single_arch" do |s|
s.platform = "ruby"
+ s.write "lib/darwin_single_arch.rb", "DARWIN_SINGLE_ARCH = '1.0 RUBY'"
end
build_gem "darwin_single_arch" do |s|
s.platform = "arm64-darwin"
+ s.write "lib/darwin_single_arch.rb", "DARWIN_SINGLE_ARCH = '1.0 arm64-darwin'"
end
build_gem "darwin_single_arch" do |s|
s.platform = "x86_64-darwin"
+ s.write "lib/darwin_single_arch.rb", "DARWIN_SINGLE_ARCH = '1.0 x86_64-darwin'"
end
end
end
@@ -94,7 +96,7 @@ RSpec.describe "bundle install across platforms" do
it "pulls in the correct architecture gem" do
lockfile <<-G
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
darwin_single_arch (1.0)
darwin_single_arch (1.0-arm64-darwin)
@@ -107,23 +109,22 @@ RSpec.describe "bundle install across platforms" do
darwin_single_arch
G
- simulate_platform "universal-darwin-21" do
- simulate_ruby_platform "universal.x86_64-darwin21" do
- install_gemfile <<-G
- source "https://gem.repo4"
+ simulate_platform "universal-darwin-21"
+ simulate_ruby_platform "universal.x86_64-darwin21" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
- gem "darwin_single_arch"
- G
+ gem "darwin_single_arch"
+ G
- expect(the_bundle).to include_gems "darwin_single_arch 1.0 x86_64-darwin"
- end
+ expect(the_bundle).to include_gems "darwin_single_arch 1.0 x86_64-darwin"
end
end
it "pulls in the correct architecture gem on arm64e macOS Ruby" do
lockfile <<-G
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
darwin_single_arch (1.0)
darwin_single_arch (1.0-arm64-darwin)
@@ -136,42 +137,41 @@ RSpec.describe "bundle install across platforms" do
darwin_single_arch
G
- simulate_platform "universal-darwin-21" do
- simulate_ruby_platform "universal.arm64e-darwin21" do
- install_gemfile <<-G
- source "https://gem.repo4"
+ simulate_platform "universal-darwin-21"
+ simulate_ruby_platform "universal.arm64e-darwin21" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
- gem "darwin_single_arch"
- G
+ gem "darwin_single_arch"
+ G
- expect(the_bundle).to include_gems "darwin_single_arch 1.0 arm64-darwin"
- end
+ expect(the_bundle).to include_gems "darwin_single_arch 1.0 arm64-darwin"
end
end
end
it "works with gems that have different dependencies" do
- simulate_platform "java" do
- install_gemfile <<-G
- source "https://gem.repo1"
+ simulate_platform "java"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
- gem "nokogiri"
- G
+ gem "nokogiri"
+ G
- expect(the_bundle).to include_gems "nokogiri 1.4.2 java", "weakling 0.0.3"
+ expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3"
- simulate_new_machine
- bundle "config set --local force_ruby_platform true"
- bundle "install"
+ simulate_new_machine
+ bundle "config set --local force_ruby_platform true"
+ bundle "install"
- expect(the_bundle).to include_gems "nokogiri 1.4.2"
- expect(the_bundle).not_to include_gems "weakling"
+ expect(the_bundle).to include_gems "nokogiri 1.4.2"
+ expect(the_bundle).not_to include_gems "weakling"
- simulate_new_machine
- bundle "install"
+ simulate_new_machine
+ simulate_platform "java"
+ bundle "install"
- expect(the_bundle).to include_gems "nokogiri 1.4.2 java", "weakling 0.0.3"
- end
+ expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3"
end
it "does not keep unneeded platforms for gems that are used" do
@@ -179,189 +179,178 @@ RSpec.describe "bundle install across platforms" do
build_gem "empyrean", "0.1.0"
build_gem "coderay", "1.1.2"
build_gem "method_source", "0.9.0"
- build_gem("spoon", "0.0.6") {|s| s.add_dependency "ffi" }
+ build_gem("spoon", "0.0.6") {|s| s.add_runtime_dependency "ffi" }
build_gem "pry", "0.11.3" do |s|
s.platform = "java"
- s.add_dependency "coderay", "~> 1.1.0"
- s.add_dependency "method_source", "~> 0.9.0"
- s.add_dependency "spoon", "~> 0.0"
+ s.add_runtime_dependency "coderay", "~> 1.1.0"
+ s.add_runtime_dependency "method_source", "~> 0.9.0"
+ s.add_runtime_dependency "spoon", "~> 0.0"
end
build_gem "pry", "0.11.3" do |s|
- s.add_dependency "coderay", "~> 1.1.0"
- s.add_dependency "method_source", "~> 0.9.0"
+ s.add_runtime_dependency "coderay", "~> 1.1.0"
+ s.add_runtime_dependency "method_source", "~> 0.9.0"
end
build_gem("ffi", "1.9.23") {|s| s.platform = "java" }
build_gem("ffi", "1.9.23")
end
- simulate_platform java do
- install_gemfile <<-G
- source "https://gem.repo4"
+ simulate_platform java
- gem "empyrean", "0.1.0"
- gem "pry"
- G
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "coderay", "1.1.2"
- c.checksum gem_repo4, "empyrean", "0.1.0"
- c.checksum gem_repo4, "ffi", "1.9.23", "java"
- c.checksum gem_repo4, "method_source", "0.9.0"
- c.checksum gem_repo4, "pry", "0.11.3", "java"
- c.checksum gem_repo4, "spoon", "0.0.6"
- end
+ gem "empyrean", "0.1.0"
+ gem "pry"
+ G
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- coderay (1.1.2)
- empyrean (0.1.0)
- ffi (1.9.23-java)
- method_source (0.9.0)
- pry (0.11.3-java)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- spoon (~> 0.0)
- spoon (0.0.6)
- ffi
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ coderay (1.1.2)
+ empyrean (0.1.0)
+ ffi (1.9.23-java)
+ method_source (0.9.0)
+ pry (0.11.3-java)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ spoon (~> 0.0)
+ spoon (0.0.6)
+ ffi
- PLATFORMS
- java
+ PLATFORMS
+ java
- DEPENDENCIES
- empyrean (= 0.1.0)
- pry
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
+ DEPENDENCIES
+ empyrean (= 0.1.0)
+ pry
- bundle "lock --add-platform ruby"
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
- checksums.checksum gem_repo4, "pry", "0.11.3"
+ bundle "lock --add-platform ruby"
- good_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- coderay (1.1.2)
- empyrean (0.1.0)
- ffi (1.9.23-java)
- method_source (0.9.0)
- pry (0.11.3)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- pry (0.11.3-java)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- spoon (~> 0.0)
- spoon (0.0.6)
- ffi
+ good_lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ coderay (1.1.2)
+ empyrean (0.1.0)
+ ffi (1.9.23-java)
+ method_source (0.9.0)
+ pry (0.11.3)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ pry (0.11.3-java)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ spoon (~> 0.0)
+ spoon (0.0.6)
+ ffi
- PLATFORMS
- java
- ruby
+ PLATFORMS
+ java
+ ruby
- DEPENDENCIES
- empyrean (= 0.1.0)
- pry
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
+ DEPENDENCIES
+ empyrean (= 0.1.0)
+ pry
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ expect(lockfile).to eq good_lockfile
+
+ bad_lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ coderay (1.1.2)
+ empyrean (0.1.0)
+ ffi (1.9.23)
+ ffi (1.9.23-java)
+ method_source (0.9.0)
+ pry (0.11.3)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ pry (0.11.3-java)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ spoon (~> 0.0)
+ spoon (0.0.6)
+ ffi
+
+ PLATFORMS
+ java
+ ruby
+
+ DEPENDENCIES
+ empyrean (= 0.1.0)
+ pry
+
+ BUNDLED WITH
+ 1.16.1
+ L
+
+ aggregate_failures do
+ lockfile bad_lockfile
+ bundle :install, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
expect(lockfile).to eq good_lockfile
- bad_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- coderay (1.1.2)
- empyrean (0.1.0)
- ffi (1.9.23)
- ffi (1.9.23-java)
- method_source (0.9.0)
- pry (0.11.3)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- pry (0.11.3-java)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- spoon (~> 0.0)
- spoon (0.0.6)
- ffi
+ lockfile bad_lockfile
+ bundle :update, :all => true, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
- PLATFORMS
- java
- ruby
+ lockfile bad_lockfile
+ bundle "update ffi", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
- DEPENDENCIES
- empyrean (= 0.1.0)
- pry
- #{checksums}
- BUNDLED WITH
- 1.16.1
- L
-
- aggregate_failures do
- lockfile bad_lockfile
- bundle :install, env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
-
- lockfile bad_lockfile
- bundle :update, all: true, env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
-
- lockfile bad_lockfile
- bundle "update ffi", env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
-
- lockfile bad_lockfile
- bundle "update empyrean", env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
-
- lockfile bad_lockfile
- bundle :lock, env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
- end
+ lockfile bad_lockfile
+ bundle "update empyrean", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
+
+ lockfile bad_lockfile
+ bundle :lock, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
end
end
it "works with gems with platform-specific dependency having different requirements order" do
- simulate_platform x64_mac do
- update_repo2 do
- build_gem "fspath", "3"
- build_gem "image_optim_pack", "1.2.3" do |s|
- s.add_dependency "fspath", ">= 2.1", "< 4"
- end
- build_gem "image_optim_pack", "1.2.3" do |s|
- s.platform = "universal-darwin"
- s.add_dependency "fspath", "< 4", ">= 2.1"
- end
+ simulate_platform x64_mac
+
+ update_repo2 do
+ build_gem "fspath", "3"
+ build_gem "image_optim_pack", "1.2.3" do |s|
+ s.add_runtime_dependency "fspath", ">= 2.1", "< 4"
end
+ build_gem "image_optim_pack", "1.2.3" do |s|
+ s.platform = "universal-darwin"
+ s.add_runtime_dependency "fspath", "< 4", ">= 2.1"
+ end
+ end
- install_gemfile <<-G
- source "https://gem.repo2"
- G
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ G
- install_gemfile <<-G
- source "https://gem.repo2"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
- gem "image_optim_pack"
- G
+ gem "image_optim_pack"
+ G
- expect(err).not_to include "Unable to use the platform-specific"
+ expect(err).not_to include "Unable to use the platform-specific"
- expect(the_bundle).to include_gem "image_optim_pack 1.2.3 universal-darwin"
- end
+ expect(the_bundle).to include_gem "image_optim_pack 1.2.3 universal-darwin"
end
it "fetches gems again after changing the version of Ruby" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
bundle "config set --local path vendor/bundle"
@@ -370,18 +359,13 @@ RSpec.describe "bundle install across platforms" do
FileUtils.mv(vendored_gems, bundled_app("vendor/bundle", Gem.ruby_engine, "1.8"))
bundle :install
- expect(vendored_gems("gems/myrack-1.0.0")).to exist
+ expect(vendored_gems("gems/rack-1.0.0")).to exist
end
it "keeps existing platforms when installing with force_ruby_platform" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "platform_specific", "1.0"
- c.checksum gem_repo1, "platform_specific", "1.0", "java"
- end
-
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0-java)
@@ -390,23 +374,20 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
platform_specific
- #{checksums}
G
bundle "config set --local force_ruby_platform true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
- checksums.checksum gem_repo1, "platform_specific", "1.0"
-
- expect(the_bundle).to include_gem "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gem "platform_specific 1.0 RUBY"
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0)
platform_specific (1.0-java)
@@ -417,7 +398,7 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
platform_specific
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -427,7 +408,7 @@ end
RSpec.describe "bundle install with platform conditionals" do
it "installs gems tagged w/ the current platforms" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
platforms :#{local_tag} do
gem "nokogiri"
@@ -439,14 +420,14 @@ RSpec.describe "bundle install with platform conditionals" do
it "does not install gems tagged w/ another platforms" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
platforms :#{not_local_tag} do
gem "nokogiri"
end
G
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
end
@@ -460,7 +441,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "activesupport"
@@ -471,14 +452,14 @@ RSpec.describe "bundle install with platform conditionals" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
activesupport (6.1.4.1)
tzinfo (~> 2.0)
tzinfo (2.0.4)
PLATFORMS
- #{local_platform}
+ #{specific_local_platform}
DEPENDENCIES
activesupport
@@ -495,7 +476,7 @@ RSpec.describe "bundle install with platform conditionals" do
it "installs gems tagged w/ the current platforms inline" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri", :platforms => :#{local_tag}
G
expect(the_bundle).to include_gems "nokogiri 1.4.2"
@@ -503,17 +484,17 @@ RSpec.describe "bundle install with platform conditionals" do
it "does not install gems tagged w/ another platforms inline" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "nokogiri", :platforms => :#{not_local_tag}
G
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
end
it "installs gems tagged w/ the current platform inline" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri", :platform => :#{local_tag}
G
expect(the_bundle).to include_gems "nokogiri 1.4.2"
@@ -521,7 +502,7 @@ RSpec.describe "bundle install with platform conditionals" do
it "doesn't install gems tagged w/ another platform inline" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri", :platform => :#{not_local_tag}
G
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
@@ -531,7 +512,7 @@ RSpec.describe "bundle install with platform conditionals" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
platform :#{not_local_tag} do
gem "foo", :git => "#{lib_path("foo-1.0")}"
end
@@ -544,7 +525,7 @@ RSpec.describe "bundle install with platform conditionals" do
bundle "config set --local force_ruby_platform true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "some_gem", :platform => :rbx
G
@@ -555,7 +536,7 @@ RSpec.describe "bundle install with platform conditionals" do
it "does not attempt to install gems from other rubies when using --local" do
bundle "config set --local force_ruby_platform true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "some_gem", platform: :ruby_22
G
@@ -567,9 +548,9 @@ RSpec.describe "bundle install with platform conditionals" do
bundle "config set --local force_ruby_platform true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", :platform => [:windows, :mswin, :mswin64, :mingw, :x64_mingw, :jruby]
+ gem "rack", :platform => [:windows, :mingw, :mswin, :x64_mingw, :jruby]
G
bundle "install"
@@ -578,15 +559,15 @@ RSpec.describe "bundle install with platform conditionals" do
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
ruby
DEPENDENCIES
- myrack
- #{checksums_section_when_enabled}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -604,7 +585,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "listen"
gem "ffi", :platform => :windows
@@ -615,23 +596,23 @@ end
RSpec.describe "when a gem has no architecture" do
it "still installs correctly" do
- simulate_platform x86_mswin32 do
- build_repo2 do
- # The rcov gem is platform mswin32, but has no arch
- build_gem "rcov" do |s|
- s.platform = Gem::Platform.new([nil, "mswin32", nil])
- s.write "lib/rcov.rb", "RCOV = '1.0.0'"
- end
+ simulate_platform x86_mswin32
+
+ build_repo2 do
+ # The rcov gem is platform mswin32, but has no arch
+ build_gem "rcov" do |s|
+ s.platform = Gem::Platform.new([nil, "mswin32", nil])
+ s.write "lib/rcov.rb", "RCOV = '1.0.0'"
end
+ end
- gemfile <<-G
- # Try to install gem with nil arch
- source "http://localgemserver.test/"
- gem "rcov"
- G
+ gemfile <<-G
+ # Try to install gem with nil arch
+ source "http://localgemserver.test/"
+ gem "rcov"
+ G
- bundle :install, artifice: "windows", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
- expect(the_bundle).to include_gems "rcov 1.0.0"
- end
+ bundle :install, :artifice => "windows", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ expect(the_bundle).to include_gems "rcov 1.0.0"
end
end
diff --git a/spec/bundler/install/gemfile/ruby_spec.rb b/spec/bundler/install/gemfile/ruby_spec.rb
index 3e15d82bbe..39f09031b7 100644
--- a/spec/bundler/install/gemfile/ruby_spec.rb
+++ b/spec/bundler/install/gemfile/ruby_spec.rb
@@ -10,77 +10,77 @@ RSpec.describe "ruby requirement" do
# requirement. This test verifies the fix, committed in bfbad5c5.
it "allows adding gems" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{Gem.ruby_version}"
- gem "myrack"
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{Gem.ruby_version}"
- gem "myrack"
- gem "myrack-obama"
+ gem "rack"
+ gem "rack-obama"
G
- expect(the_bundle).to include_gems "myrack-obama 1.0"
+ expect(the_bundle).to include_gems "rack-obama 1.0"
end
it "allows removing the ruby version requirement" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "~> #{Gem.ruby_version}"
- gem "myrack"
+ gem "rack"
G
expect(lockfile).to include("RUBY VERSION")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(lockfile).not_to include("RUBY VERSION")
end
it "allows changing the ruby version requirement to something compatible" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= #{current_ruby_minor}"
- gem "myrack"
+ gem "rack"
G
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
expect(locked_ruby_version).to eq(Bundler::RubyVersion.system)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= #{Gem.ruby_version}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(locked_ruby_version).to eq(Bundler::RubyVersion.system)
end
it "allows changing the ruby version requirement to something incompatible" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= 1.0.0"
- gem "myrack"
+ gem "rack"
G
lockfile <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
RUBY VERSION
ruby 2.1.4p422
@@ -92,66 +92,32 @@ RSpec.describe "ruby requirement" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= #{current_ruby_minor}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(locked_ruby_version).to eq(Bundler::RubyVersion.system)
end
it "allows requirements with trailing whitespace" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{Gem.ruby_version}\\n \t\\n"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "fails gracefully with malformed requirements" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= 0", "-.\\0"
- gem "myrack"
+ gem "rack"
G
expect(err).to include("There was an error parsing") # i.e. DSL error, not error template
end
-
- it "allows picking up ruby version from a file" do
- create_file ".ruby-version", Gem.ruby_version.to_s
-
- install_gemfile <<-G
- source "https://gem.repo1"
- ruby file: ".ruby-version"
- gem "myrack"
- G
-
- expect(lockfile).to include("RUBY VERSION")
- end
-
- it "reads the ruby version file from the right folder when nested Gemfiles are involved" do
- create_file ".ruby-version", Gem.ruby_version.to_s
-
- gemfile <<-G
- source "https://gem.repo1"
- ruby file: ".ruby-version"
- gem "myrack"
- G
-
- nested_dir = bundled_app(".ruby-lsp")
-
- FileUtils.mkdir nested_dir
-
- gemfile ".ruby-lsp/Gemfile", <<-G
- eval_gemfile(File.expand_path("../Gemfile", __dir__))
- G
-
- bundle "install", dir: nested_dir
-
- expect(bundled_app(".ruby-lsp/Gemfile.lock").read).to include("RUBY VERSION")
- end
end
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb
index 84af5c0d06..2199d8bedc 100644
--- a/spec/bundler/install/gemfile/sources_spec.rb
+++ b/spec/bundler/install/gemfile/sources_spec.rb
@@ -2,167 +2,85 @@
RSpec.describe "bundle install with gems on multiple sources" do
# repo1 is built automatically before all of the specs run
- # it contains myrack-obama 1.0.0 and myrack 0.9.1 & 1.0.0 amongst other gems
+ # it contains rack-obama 1.0.0 and rack 0.9.1 & 1.0.0 amongst other gems
context "without source affinity" do
before do
- # Oh no! Someone evil is trying to hijack myrack :(
+ # Oh no! Someone evil is trying to hijack rack :(
# need this to be broken to check for correct source ordering
- build_repo3 do
- build_gem "myrack", repo3_myrack_version do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_repo gem_repo3 do
+ build_gem "rack", repo3_rack_version do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
context "with multiple toplevel sources" do
- let(:repo3_myrack_version) { "1.0.0" }
+ let(:repo3_rack_version) { "1.0.0" }
before do
gemfile <<-G
source "https://gem.repo3"
source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack"
+ gem "rack-obama"
+ gem "rack"
G
end
- it "refuses to install mismatched checksum because one gem has been tampered with", bundler: "< 3" do
- lockfile <<~L
- GEM
- remote: https://gem.repo3/
- remote: https://gem.repo1/
- specs:
- myrack (1.0.0)
+ it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "< 3" do
+ bundle :install, :artifice => "compact_index"
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- depends_on_myrack!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle :install, artifice: "compact_index", raise_on_error: false
-
- 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_to_lock(gem_repo1, "myrack", "1.0.0")}
- from the API at https://gem.repo1/
- #{checksum_to_lock(gem_repo3, "myrack", "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 'myrack' was found in multiple sources.")
- expect(err).to include("Installed from: https://gem.repo1")
- expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 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
context "when different versions of the same gem are in multiple sources" do
- let(:repo3_myrack_version) { "1.2" }
+ let(:repo3_rack_version) { "1.2" }
before do
gemfile <<-G
source "https://gem.repo3"
source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack", "1.0.0" # force it to install the working version in repo1
+ gem "rack-obama"
+ gem "rack", "1.0.0" # force it to install the working version in repo1
G
end
- it "warns about ambiguous gems, but installs anyway", bundler: "< 3" do
- bundle :install, artifice: "compact_index"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
+ it "warns about ambiguous gems, but installs anyway", :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("myrack-obama 1.0.0", "myrack 1.0.0", source: "remote1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
end
- it "fails", bundler: "3" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ 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
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_digest(gem_repo4, "foo", "1.0")
- 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
- # Oh no! Someone evil is trying to hijack myrack :(
+ # Oh no! Someone evil is trying to hijack rack :(
# need this to be broken to check for correct source ordering
- build_repo3 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_repo gem_repo3 do
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
- build_gem "myrack-obama" do |s|
- s.add_dependency "myrack"
+ build_gem "rack-obama" do |s|
+ s.add_dependency "rack"
end
end
@@ -170,76 +88,76 @@ RSpec.describe "bundle install with gems on multiple sources" do
source "https://gem.repo3"
source "https://gem.repo1" do
gem "thin" # comes first to test name sorting
- gem "myrack"
+ gem "rack"
end
- gem "myrack-obama" # should come from repo3!
+ gem "rack-obama" # should come from repo3!
G
end
it "installs the gems without any warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("myrack-obama 1.0.0")
- expect(the_bundle).to include_gems("myrack 1.0.0", source: "remote1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote1")
end
it "can cache and deploy" do
- bundle :cache, artifice: "compact_index"
+ bundle :cache, :artifice => "compact_index"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- expect(bundled_app("vendor/cache/myrack-obama-1.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-obama-1.0.gem")).to exist
bundle "config set --local deployment true"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
- expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0")
end
end
context "with sources set by an option" do
before do
- # Oh no! Someone evil is trying to hijack myrack :(
+ # Oh no! Someone evil is trying to hijack rack :(
# need this to be broken to check for correct source ordering
- build_repo3 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_repo gem_repo3 do
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
- build_gem "myrack-obama" do |s|
- s.add_dependency "myrack"
+ build_gem "rack-obama" do |s|
+ s.add_dependency "rack"
end
end
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo3"
- gem "myrack-obama" # should come from repo3!
- gem "myrack", :source => "https://gem.repo1"
+ gem "rack-obama" # should come from repo3!
+ gem "rack", :source => "https://gem.repo1"
G
end
it "installs the gems without any warning" do
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0")
end
end
context "when a pinned gem has an indirect dependency in the pinned source" do
before do
- build_repo3 do
- build_gem "depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "myrack"
+ build_repo gem_repo3 do
+ build_gem "depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "rack"
end
end
- # we need a working myrack gem in repo3
+ # we need a working rack gem in repo3
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
gemfile <<-G
source "https://gem.repo2"
source "https://gem.repo3" do
- gem "depends_on_myrack"
+ gem "depends_on_rack"
end
G
end
@@ -250,9 +168,9 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the same source without any warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
@@ -260,57 +178,57 @@ RSpec.describe "bundle install with gems on multiple sources" do
before do
# need this to be broken to check for correct source ordering
build_repo gem_repo2 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
it "installs from the same source without any warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
- expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
# In https://github.com/bundler/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
- expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
end
context "when a pinned gem has an indirect dependency in a different source" do
before do
- # In these tests, we need a working myrack gem in repo2 and not repo3
+ # In these tests, we need a working rack gem in repo2 and not repo3
- build_repo3 do
- build_gem "depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "myrack"
+ build_repo gem_repo3 do
+ build_gem "depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "rack"
end
end
build_repo gem_repo2 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
context "and not in any other sources" do
before do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo2"
source "https://gem.repo3" do
- gem "depends_on_myrack"
+ gem "depends_on_rack"
end
G
end
it "installs from the other source without any warning" do
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
end
@@ -320,138 +238,46 @@ RSpec.describe "bundle install with gems on multiple sources" do
source "https://gem.repo1"
source "https://gem.repo2"
source "https://gem.repo3" do
- gem "depends_on_myrack"
+ gem "depends_on_rack"
end
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_to_lock(gem_repo2, "myrack", "1.0.0")}
- from the API at https://gem.repo2/
- #{checksum_to_lock(gem_repo1, "myrack", "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
- myrack_checksum = "c0ffee11" * 8
- bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => myrack_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.
- myrack (1.0.0) sha256=#{myrack_checksum}
- from the API at https://gem.repo2/
- and the API at https://gem.repo1/
- #{checksum_to_lock(gem_repo2, "myrack", "1.0.0")}
- from the gem at #{default_bundle_path("cache", "myrack-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", "myrack-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_digest(gem_repo2, "myrack", "1.0.0")
- bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => gem_checksum, "DEBUG" => "1" }
-
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
+ 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")
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo3, "depends_on_myrack", "1.0.1"
- c.checksum gem_repo2, "myrack", "1.0.0"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo1/
remote: https://gem.repo2/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
GEM
remote: https://gem.repo3/
specs:
- depends_on_myrack (1.0.1)
- myrack
+ depends_on_rack (1.0.1)
+ rack
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
- depends_on_myrack!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- previous_lockfile = lockfile
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 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"
- bundle :install, artifice: "compact_index"
+ depends_on_rack!
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(err).to include("Installed from: https://gem.repo2")
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "depends_on_myrack", "1.0.1"
- c.no_checksum "myrack", "1.0.0"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo1/
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
-
- GEM
- remote: https://gem.repo3/
- specs:
- depends_on_myrack (1.0.1)
- myrack
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- depends_on_myrack!
- #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
previous_lockfile = lockfile
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
expect(lockfile).to eq(previous_lockfile)
end
- it "fails", bundler: "3" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ 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
@@ -461,37 +287,37 @@ RSpec.describe "bundle install with gems on multiple sources" do
before do
# need this to be broken to check for correct source ordering
build_repo gem_repo2 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
gemfile <<-G
- source "https://gem.repo3" # contains depends_on_myrack
- source "https://gem.repo2" # contains broken myrack
+ source "https://gem.repo3" # contains depends_on_rack
+ source "https://gem.repo2" # contains broken rack
- gem "depends_on_myrack" # installed from gem_repo3
- gem "myrack", :source => "https://gem.repo1"
+ gem "depends_on_rack" # installed from gem_repo3
+ gem "rack", :source => "https://gem.repo1"
G
end
- it "installs the dependency from the pinned source without warning", bundler: "< 3" do
- bundle :install, artifice: "compact_index"
+ it "installs the dependency from the pinned source without warning", :bundler => "< 3" do
+ bundle :install, :artifice => "compact_index"
- expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
+ expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
# In https://github.com/rubygems/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
- expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
+ expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
- it "fails", bundler: "3" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ 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
@@ -502,7 +328,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
before do
build_repo2
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "private_gem_1", "1.0.0"
build_gem "private_gem_2", "1.0.0"
end
@@ -519,16 +345,16 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "fails" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository https://gem.repo2/ or installed locally.")
end
end
- context "when an indirect dependency can't be found in the aggregate rubygems source", bundler: "< 3" do
+ context "when an indirect dependency can't be found in the aggregate rubygems source", :bundler => "< 3" do
before do
build_repo2
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "depends_on_missing", "1.0.1" do |s|
s.add_dependency "missing"
end
@@ -544,13 +370,13 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "fails" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to end_with <<~E.strip
Could not find compatible versions
Because every version of depends_on_missing depends on missing >= 0
and missing >= 0 could not be found in any of the sources,
- depends_on_missing cannot be used.
+ every version of depends_on_missing is forbidden.
So, because Gemfile depends on depends_on_missing >= 0,
version solving has failed.
E
@@ -560,19 +386,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a top-level gem has an indirect dependency" do
before do
build_repo gem_repo2 do
- build_gem "depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "rack"
end
end
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "unrelated_gem", "1.0.0"
end
gemfile <<-G
source "https://gem.repo2"
- gem "depends_on_myrack"
+ gem "depends_on_rack"
source "https://gem.repo3" do
gem "unrelated_gem"
@@ -583,37 +409,37 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "and the dependency is only in the top-level source" do
before do
update_repo gem_repo2 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
it "installs the dependency from the top-level source without warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", "unrelated_gem 1.0.0")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote2")
- expect(the_bundle).to include_gems("unrelated_gem 1.0.0", source: "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2")
+ expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3")
end
end
context "and the dependency is only in a pinned source" do
before do
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
it "does not find the dependency" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to end_with <<~E.strip
Could not find compatible versions
- Because every version of depends_on_myrack depends on myrack >= 0
- and myrack >= 0 could not be found in rubygems repository https://gem.repo2/ or installed locally,
- depends_on_myrack cannot be used.
- So, because Gemfile depends on depends_on_myrack >= 0,
+ Because every version of depends_on_rack depends on rack >= 0
+ and rack >= 0 could not be found in rubygems repository https://gem.repo2/ or installed locally,
+ every version of depends_on_rack is forbidden.
+ So, because Gemfile depends on depends_on_rack >= 0,
version solving has failed.
E
end
@@ -622,36 +448,36 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "and the dependency is in both the top-level and a pinned source" do
before do
update_repo gem_repo2 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
it "installs the dependency from the top-level source without warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
- expect(run("require 'myrack'; puts MYRACK")).to eq("1.0.0")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", "unrelated_gem 1.0.0")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote2")
- expect(the_bundle).to include_gems("unrelated_gem 1.0.0", source: "remote3")
+ expect(run("require 'rack'; puts RACK")).to eq("1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2")
+ expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3")
end
end
end
context "when a scoped gem has a deeply nested indirect dependency" do
before do
- build_repo3 do
- build_gem "depends_on_depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "depends_on_myrack"
+ build_repo gem_repo3 do
+ build_gem "depends_on_depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "depends_on_rack"
end
- build_gem "depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "rack"
end
end
@@ -659,7 +485,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
source "https://gem.repo2"
source "https://gem.repo3" do
- gem "depends_on_depends_on_myrack"
+ gem "depends_on_depends_on_rack"
end
G
end
@@ -667,15 +493,15 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "and the dependency is only in the top-level source" do
before do
update_repo gem_repo2 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
it "installs the dependency from the top-level source" do
- bundle :install, artifice: "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_myrack 1.0.1", "depends_on_myrack 1.0.1", "myrack 1.0.0")
- expect(the_bundle).to include_gems("myrack 1.0.0", source: "remote2")
- expect(the_bundle).to include_gems("depends_on_depends_on_myrack 1.0.1", "depends_on_myrack 1.0.1", source: "remote3")
+ bundle :install, :artifice => "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote2")
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", :source => "remote3")
end
end
@@ -684,32 +510,32 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_repo2
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
it "installs the dependency from the pinned source" do
- bundle :install, artifice: "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_myrack 1.0.1", "depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ bundle :install, :artifice => "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
context "and the dependency is in both the top-level and a pinned source" do
before do
update_repo gem_repo2 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
it "installs the dependency from the pinned source without warning" do
- bundle :install, artifice: "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_myrack 1.0.1", "depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ bundle :install, :artifice => "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
end
@@ -742,12 +568,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
build_gem "minitest", "5.14.3"
- build_gem "myrack", "2.2.3"
+ build_gem "rack", "2.2.3"
build_gem "redis", "4.2.5"
build_gem "sidekiq", "6.1.3" do |s|
s.add_dependency "connection_pool", ">= 2.2.2"
- s.add_dependency "myrack", "~> 2.0"
+ s.add_dependency "rack", "~> 2.0"
s.add_dependency "redis", ">= 4.2.0"
end
@@ -764,7 +590,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "zeitwerk", "2.4.2"
end
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "sidekiq-pro", "5.2.1" do |s|
s.add_dependency "connection_pool", ">= 2.2.3"
s.add_dependency "sidekiq", ">= 6.1.0"
@@ -783,21 +609,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
- @locked_checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "activesupport", "6.0.3.4"
- c.checksum gem_repo2, "concurrent-ruby", "1.1.8"
- c.checksum gem_repo2, "connection_pool", "2.2.3"
- c.checksum gem_repo2, "i18n", "1.8.9"
- c.checksum gem_repo2, "minitest", "5.14.3"
- c.checksum gem_repo2, "myrack", "2.2.3"
- c.checksum gem_repo2, "redis", "4.2.5"
- c.checksum gem_repo2, "sidekiq", "6.1.3"
- c.checksum gem_repo3, "sidekiq-pro", "5.2.1"
- c.checksum gem_repo2, "thread_safe", "0.3.6"
- c.checksum gem_repo2, "tzinfo", "1.2.9"
- c.checksum gem_repo2, "zeitwerk", "2.4.2"
- end
-
lockfile <<~L
GEM
remote: https://gem.repo2/
@@ -814,11 +625,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
- myrack (2.2.3)
+ rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
- myrack (~> 2.0)
+ rack (~> 2.0)
redis (>= 4.2.0)
sidekiq-pro (5.2.1)
connection_pool (>= 2.2.3)
@@ -829,19 +640,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
zeitwerk (2.4.2)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
- #{@locked_checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "does not install newer versions but updates the lockfile format when running bundle install in non frozen mode, and doesn't warn" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).to be_empty
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
@@ -866,11 +677,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
- myrack (2.2.3)
+ rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
- myrack (~> 2.0)
+ rack (~> 2.0)
redis (>= 4.2.0)
thread_safe (0.3.6)
tzinfo (1.2.9)
@@ -885,22 +696,22 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
- #{@locked_checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "does not install newer versions or generate lockfile changes when running bundle install in frozen mode, and warns", bundler: "< 3" do
+ it "does not install newer versions or generate lockfile changes when running bundle install in frozen mode, and warns", :bundler => "< 3" do
initial_lockfile = lockfile
bundle "config set --local frozen true"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -914,11 +725,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(lockfile).to eq(initial_lockfile)
end
- it "fails when running bundle install in frozen mode", bundler: "3" do
+ it "fails when running bundle install in frozen mode", :bundler => "3" do
initial_lockfile = lockfile
bundle "config set --local frozen true"
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -926,21 +737,15 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "splits sections and upgrades gems when running bundle update, and doesn't warn" do
- bundle "update --all", artifice: "compact_index"
+ bundle "update --all", :artifice => "compact_index"
expect(err).to be_empty
expect(the_bundle).not_to include_gems("activesupport 6.0.3.4")
expect(the_bundle).to include_gems("activesupport 6.1.2.1")
- @locked_checksums.checksum gem_repo2, "activesupport", "6.1.2.1"
-
expect(the_bundle).not_to include_gems("tzinfo 1.2.9")
expect(the_bundle).to include_gems("tzinfo 2.0.4")
- @locked_checksums.checksum gem_repo2, "tzinfo", "2.0.4"
- @locked_checksums.delete "thread_safe"
-
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
- @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9"
expect(lockfile).to eq <<~L
GEM
@@ -957,11 +762,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
- myrack (2.2.3)
+ rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
- myrack (~> 2.0)
+ rack (~> 2.0)
redis (>= 4.2.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
@@ -975,19 +780,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
- #{@locked_checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "upgrades the lockfile format and upgrades the requested gem when running bundle update with an argument" do
- bundle "update concurrent-ruby", artifice: "compact_index"
+ bundle "update concurrent-ruby", :artifice => "compact_index"
expect(err).to be_empty
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
@@ -997,8 +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")
- @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9"
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo2/
@@ -1014,11 +817,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
- myrack (2.2.3)
+ rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
- myrack (~> 2.0)
+ rack (~> 2.0)
redis (>= 4.2.0)
thread_safe (0.3.6)
tzinfo (1.2.9)
@@ -1033,12 +836,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
- #{@locked_checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1047,8 +850,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a top-level gem has an indirect dependency present in the default source, but with a different version from the one resolved" do
before do
- build_lib "activesupport", "7.0.0.alpha", path: lib_path("rails/activesupport")
- build_lib "rails", "7.0.0.alpha", path: lib_path("rails") do |s|
+ build_lib "activesupport", "7.0.0.alpha", :path => lib_path("rails/activesupport")
+ build_lib "rails", "7.0.0.alpha", :path => lib_path("rails") do |s|
s.add_dependency "activesupport", "= 7.0.0.alpha"
end
@@ -1070,17 +873,17 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs all gems without warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", "rails 7.0.0.alpha")
- expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", source: "path@#{lib_path("rails/activesupport")}")
- expect(the_bundle).to include_gems("rails 7.0.0.alpha", source: "path@#{lib_path("rails")}")
+ expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", :source => "path@#{lib_path("rails/activesupport")}")
+ expect(the_bundle).to include_gems("rails 7.0.0.alpha", :source => "path@#{lib_path("rails")}")
end
end
context "when a pinned gem has an indirect dependency with more than one level of indirection in the default source " do
before do
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "handsoap", "0.2.5.5" do |s|
s.add_dependency "nokogiri", ">= 1.2.3"
end
@@ -1106,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
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo3, "handsoap", "0.2.5.5"
- c.checksum gem_repo2, "nokogiri", "1.11.1"
- c.checksum gem_repo2, "racca", "1.5.2"
- end
-
expected_lockfile = <<~L
GEM
remote: https://gem.repo2/
@@ -1127,41 +924,41 @@ RSpec.describe "bundle install with gems on multiple sources" do
nokogiri (>= 1.2.3)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
handsoap!
nokogiri
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
- bundle "install --verbose", artifice: "compact_index"
+ bundle "install --verbose", :artifice => "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
- expect(the_bundle).to include_gems("handsoap 0.2.5.5", source: "remote3")
- expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", source: "remote2")
+ expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
+ expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
expect(lockfile).to eq(expected_lockfile)
# Even if the gems are already installed
FileUtils.rm bundled_app_lock
- bundle "install --verbose", artifice: "compact_index"
+ bundle "install --verbose", :artifice => "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
- expect(the_bundle).to include_gems("handsoap 0.2.5.5", source: "remote3")
- expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", source: "remote2")
+ expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
+ expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
expect(lockfile).to eq(expected_lockfile)
end
end
context "with a gem that is only found in the wrong source" do
before do
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "not_in_repo1", "1.0.0"
end
- install_gemfile <<-G, artifice: "compact_index", raise_on_error: false
+ install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
source "https://gem.repo3"
gem "not_in_repo1", :source => "https://gem.repo1"
G
@@ -1174,7 +971,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "with an existing lockfile" do
before do
- system_gems "myrack-0.9.1", "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-0.9.1", "rack-1.0.0", :path => default_bundle_path
lockfile <<-L
GEM
@@ -1184,26 +981,26 @@ RSpec.describe "bundle install with gems on multiple sources" do
GEM
remote: https://gem.repo3
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
- myrack!
+ rack!
L
gemfile <<-G
source "https://gem.repo1"
source "https://gem.repo3" do
- gem 'myrack'
+ gem 'rack'
end
G
end
# Reproduction of https://github.com/rubygems/bundler/issues/3298
it "does not unlock the installed gem on exec" do
- expect(the_bundle).to include_gems("myrack 0.9.1")
+ expect(the_bundle).to include_gems("rack 0.9.1")
end
end
@@ -1214,14 +1011,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
remote: https://gem.repo1/
remote: https://gem.repo3/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
- myrack!
- #{checksums_section}
+ rack!
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1236,13 +1033,13 @@ RSpec.describe "bundle install with gems on multiple sources" do
GEM
remote: https://gem.repo3/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
- myrack!
+ rack!
BUNDLED WITH
#{Bundler::VERSION}
@@ -1250,62 +1047,34 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
before do
- build_repo3 do
- build_gem "myrack", "0.9.1"
+ build_repo gem_repo3 do
+ build_gem "rack", "0.9.1"
end
gemfile <<-G
source "https://gem.repo1"
source "https://gem.repo3" do
- gem 'myrack'
+ gem 'rack'
end
G
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"
+ bundle "install", :artifice => "compact_index"
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.")
- expect(the_bundle).to include_gems("myrack 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_digest(gem_repo1, "myrack", "0.9.1")
- api_checksum3 = checksum_digest(gem_repo3, "myrack", "0.9.1")
-
- 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.
- myrack (0.9.1) sha256=#{api_checksum3}
- from the API at https://gem.repo3/
- myrack (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
+ expect(the_bundle).to include_gems("rack 0.9.1", :source => "remote3")
end
- it "refuses to install the existing lockfile and prints an error", bundler: "3" do
+ 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.")
@@ -1318,14 +1087,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_lib "foo"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :source => "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :source => "https://gem.repo1"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
end
it "does not unlock the non-path gem after install" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
bundle %(exec ruby -e 'puts "OK"')
@@ -1336,17 +1105,17 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when an older version of the same gem also ships with Ruby" do
before do
- system_gems "myrack-0.9.1"
+ system_gems "rack-0.9.1"
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
- gem "myrack" # should come from repo1!
+ gem "rack" # should come from repo1!
G
end
it "installs the gems without any warning" do
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
end
@@ -1361,13 +1130,13 @@ RSpec.describe "bundle install with gems on multiple sources" do
# Installing this gemfile...
gemfile <<-G
source 'https://gem.repo1'
- gem 'myrack'
+ gem 'rack'
gem 'foo', '~> 0.1', :source => 'https://gem.repo4'
gem 'bar', '~> 0.1', :source => 'https://gem.repo4'
G
bundle "config set --local path ../gems/system"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
# And then we add some new versions...
update_repo4 do
@@ -1378,9 +1147,9 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "allows them to be unlocked separately" do
# And install this gemfile, updating only foo.
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source 'https://gem.repo1'
- gem 'myrack'
+ gem 'rack'
gem 'foo', '~> 0.2', :source => 'https://gem.repo4'
gem 'bar', '~> 0.1', :source => 'https://gem.repo4'
G
@@ -1393,8 +1162,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "re-resolving" do
context "when there is a mix of sources in the gemfile" do
before do
- build_repo3 do
- build_gem "myrack"
+ build_repo gem_repo3 do
+ build_gem "rack"
end
build_lib "path1"
@@ -1402,12 +1171,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_git "git1"
build_git "git2"
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
gem "rails"
source "https://gem.repo3" do
- gem "myrack"
+ gem "rack"
end
gem "path1", :path => "#{lib_path("path1-1.0")}"
@@ -1418,7 +1187,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "does not re-resolve" do
- bundle :install, artifice: "compact_index", verbose: true
+ bundle :install, :artifice => "compact_index", :verbose => true
expect(out).to include("using resolution from the lockfile")
expect(out).not_to include("re-resolving dependencies")
end
@@ -1427,28 +1196,28 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a gem is installed to system gems" do
before do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
- gem "myrack"
+ gem "rack"
G
end
context "and the gemfile changes" do
it "is still able to find that gem from remote sources" do
build_repo4 do
- build_gem "myrack", "2.0.1.1.forked"
+ build_gem "rack", "2.0.1.1.forked"
build_gem "thor", "0.19.1.1.forked"
end
# When this gemfile is installed...
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
source "https://gem.repo4" do
- gem "myrack", "2.0.1.1.forked"
+ gem "rack", "2.0.1.1.forked"
gem "thor"
end
- gem "myrack-obama"
+ gem "rack-obama"
G
# Then we change the Gemfile by adding a version to thor
@@ -1456,47 +1225,47 @@ RSpec.describe "bundle install with gems on multiple sources" do
source "https://gem.repo1"
source "https://gem.repo4" do
- gem "myrack", "2.0.1.1.forked"
+ gem "rack", "2.0.1.1.forked"
gem "thor", "0.19.1.1.forked"
end
- gem "myrack-obama"
+ gem "rack-obama"
G
- # But we should still be able to find myrack 2.0.1.1.forked and install it
- bundle :install, artifice: "compact_index"
+ # But we should still be able to find rack 2.0.1.1.forked and install it
+ bundle :install, :artifice => "compact_index"
end
end
end
describe "source changed to one containing a higher version of a dependency" do
before do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
- gem "myrack"
+ gem "rack"
G
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "bar"
end
- build_lib("gemspec_test", path: tmp("gemspec_test")) do |s|
+ build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
s.add_dependency "bar", "=1.0.0"
end
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo2"
- gem "myrack"
- gemspec :path => "#{tmp("gemspec_test")}"
+ gem "rack"
+ gemspec :path => "#{tmp.join("gemspec_test")}"
G
end
it "conservatively installs the existing locked version" do
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
end
@@ -1506,18 +1275,18 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "bar"
end
- build_lib("gemspec_test", path: tmp("gemspec_test")) do |s|
+ build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
s.add_development_dependency "bar"
end
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
source "https://gem.repo4" do
gem "bar"
end
- gemspec :path => "#{tmp("gemspec_test")}"
+ gemspec :path => "#{tmp.join("gemspec_test")}"
G
end
@@ -1535,7 +1304,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "example", "1.0.2"
end
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo4"
gem "example", :source => "https://gem.repo2"
@@ -1544,9 +1313,9 @@ RSpec.describe "bundle install with gems on multiple sources" do
bundle "info example"
expect(out).to include("example (0.1.0)")
- system_gems "example-1.0.2", path: default_bundle_path, gem_repo: gem_repo4
+ system_gems "example-1.0.2", :path => default_bundle_path, :gem_repo => gem_repo4
- bundle "update example --verbose", artifice: "compact_index"
+ bundle "update example --verbose", :artifice => "compact_index"
expect(out).not_to include("Using example 1.0.2")
expect(out).to include("Using example 0.1.0")
end
@@ -1560,9 +1329,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
- ruby <<~R, raise_on_error: false
- require 'bundler/setup'
- R
+ simulate_bundler_version_when_missing_prerelease_default_gem_activation do
+ ruby <<~R, :raise_on_error => false
+ require 'bundler/setup'
+ R
+ end
expect(last_command).to be_failure
expect(err).to include("Could not find gem 'example' in locally installed gems.")
@@ -1577,36 +1348,36 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
- bundle "install", artifice: nil, raise_on_error: false
+ bundle "install", :artifice => nil, :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("Could not reach host gem.repo4. Check your network connection and try again.")
end
- context "when an indirect dependency is available from multiple ambiguous sources", bundler: "< 3" do
+ context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "< 3" do
it "succeeds but warns, suggesting a source block" do
build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack" do |s|
+ s.add_dependency "rack"
end
- build_gem "myrack"
+ build_gem "rack"
end
- install_gemfile <<-G, artifice: "compact_index_extra_api", raise_on_error: false
- source "https://global.source"
+ install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
- source "https://scoped.source/extra" do
- gem "depends_on_myrack"
+ source "https://gem.repo4" do
+ gem "depends_on_rack"
end
- source "https://scoped.source" do
+ source "https://gem.repo1" do
gem "thin"
end
G
- expect(err).to eq <<~EOS.strip
- Warning: The gem 'myrack' was found in multiple relevant sources.
- * rubygems repository https://scoped.source/
- * rubygems repository https://scoped.source/extra/
+ 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/
You should add this gem to the source block for the source you wish it to be installed from.
EOS
expect(last_command).to be_success
@@ -1614,31 +1385,29 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "when an indirect dependency is available from multiple ambiguous sources", bundler: "3" do
+ context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "3" do
it "raises, suggesting a source block" do
build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack" do |s|
+ s.add_dependency "rack"
end
- build_gem "myrack"
+ build_gem "rack"
end
- install_gemfile <<-G, artifice: "compact_index_extra_api", raise_on_error: false
- source "https://global.source"
-
- source "https://scoped.source/extra" do
- gem "depends_on_myrack"
+ install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo4" do
+ gem "depends_on_rack"
end
-
- source "https://scoped.source" do
+ source "https://gem.repo1" do
gem "thin"
end
G
expect(last_command).to be_failure
- expect(err).to eq <<~EOS.strip
- The gem 'myrack' was found in multiple relevant sources.
- * rubygems repository https://scoped.source/
- * rubygems repository https://scoped.source/extra/
+ 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/
You must add this gem to the source block for the source you wish it to be installed from.
EOS
expect(the_bundle).not_to be_locked
@@ -1679,23 +1448,16 @@ RSpec.describe "bundle install with gems on multiple sources" do
mime-types (3.3.1)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
capybara (~> 2.5.0)
mime-types (~> 3.0)!
-
- CHECKSUMS
L
end
it "upgrades the lockfile correctly" do
- bundle "lock --update", artifice: "compact_index"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "capybara", "2.5.0"
- c.checksum gem_repo4, "mime-types", "3.0.0"
- end
+ bundle "lock --update", :artifice => "compact_index"
expect(lockfile).to eq <<~L
GEM
@@ -1710,12 +1472,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
mime-types (3.0.0)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
capybara (~> 2.5.0)
mime-types (~> 3.0)!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1742,38 +1504,33 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
- gem "ruport", "= 1.7.0.3", :source => "https://gem.repo4/extra"
+ gem "ruport", "= 1.7.0.3", :source => "https://localgemserver.test/extra"
G
end
it "handles that fine" do
- bundle "install", artifice: "compact_index_extra"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "pdf-writer", "1.1.8"
- c.checksum gem_repo2, "ruport", "1.7.0.3"
- end
+ bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
pdf-writer (1.1.8)
GEM
- remote: https://gem.repo4/extra/
+ remote: https://localgemserver.test/extra/
specs:
ruport (1.7.0.3)
pdf-writer (= 1.1.8)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
ruport (= 1.7.0.3)!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1800,38 +1557,33 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
- gem "ruport", "= 1.7.0.3", :source => "https://gem.repo4/extra"
+ gem "ruport", "= 1.7.0.3", :source => "https://localgemserver.test/extra"
G
end
it "handles that fine" do
- bundle "install", artifice: "compact_index_extra"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "pdf-writer", "1.1.8"
- c.checksum gem_repo2, "ruport", "1.7.0.3"
- end
+ bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
pdf-writer (1.1.8)
GEM
- remote: https://gem.repo4/extra/
+ remote: https://localgemserver.test/extra/
specs:
ruport (1.7.0.3)
pdf-writer (= 1.1.8)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
ruport (= 1.7.0.3)!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1852,31 +1604,27 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
gem "pdf-writer", "= 1.1.8"
G
end
it "handles that fine" do
- bundle "install --verbose", artifice: "endpoint"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "pdf-writer", "1.1.8"
- end
+ bundle "install --verbose", :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
pdf-writer (1.1.8)
PLATFORMS
- #{lockfile_platforms}
+ #{specific_local_platform}
DEPENDENCIES
pdf-writer (= 1.1.8)
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1895,7 +1643,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "example", "1.0.0"
end
- install_gemfile <<~G, artifice: "compact_index"
+ install_gemfile <<~G, :artifice => "compact_index"
source "https://gem.repo2"
source "https://gem.repo4" do
@@ -1915,76 +1663,10 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "shows a proper error message and does not generate a corrupted lockfile" do
expect do
- bundle :install, artifice: "compact_index", raise_on_error: false, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ bundle :install, :artifice => "compact_index", :raise_on_error => false, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end.not_to change { lockfile }
expect(err).to include("Could not find gem 'example' in rubygems repository https://gem.repo4/")
end
end
-
- context "when a gem has versions in two sources, but only the locked one has updates" do
- let(:original_lockfile) do
- <<~L
- GEM
- remote: https://main.source/
- specs:
- activesupport (1.0)
- bigdecimal
- bigdecimal (1.0.0)
-
- GEM
- remote: https://main.source/extra/
- specs:
- foo (1.0)
- bigdecimal
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- activesupport
- foo!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- before do
- build_repo3 do
- build_gem "activesupport" do |s|
- s.add_dependency "bigdecimal"
- end
-
- build_gem "bigdecimal", "1.0.0"
- build_gem "bigdecimal", "3.3.1"
- end
-
- build_repo4 do
- build_gem "foo" do |s|
- s.add_dependency "bigdecimal"
- end
-
- build_gem "bigdecimal", "1.0.0"
- end
-
- gemfile <<~G
- source "https://main.source"
-
- gem "activesupport"
-
- source "https://main.source/extra" do
- gem "foo"
- end
- G
-
- lockfile original_lockfile
- end
-
- it "properly upgrades the lockfile when updating that specific gem" do
- bundle "update bigdecimal --conservative", artifice: "compact_index_extra_api", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo3.to_s }
-
- expect(lockfile).to eq original_lockfile.gsub("bigdecimal (1.0.0)", "bigdecimal (3.3.1)")
- end
- end
end
diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb
index a1feadb113..2f82a9f9f3 100644
--- a/spec/bundler/install/gemfile/specific_platform_spec.rb
+++ b/spec/bundler/install/gemfile/specific_platform_spec.rb
@@ -2,7 +2,7 @@
RSpec.describe "bundle install with specific platforms" do
let(:google_protobuf) { <<-G }
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "google-protobuf"
G
@@ -11,11 +11,11 @@ RSpec.describe "bundle install with specific platforms" do
setup_multiplatform_gem
install_gemfile(google_protobuf)
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- expect(the_bundle.locked_gems.platforms).to include(pl("x86_64-darwin-15"))
+ expect(the_bundle.locked_gems.platforms).to eq([pl("x86_64-darwin-15")])
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(
- "google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin"
- )
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[
+ google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
+ ])
end
end
@@ -26,14 +26,14 @@ RSpec.describe "bundle install with specific platforms" do
system_gems "bundler-2.1.4"
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
- install_gemfile(google_protobuf, env: { "BUNDLER_VERSION" => "2.1.4" })
+ install_gemfile(google_protobuf, :env => { "BUNDLER_VERSION" => "2.1.4" })
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
google-protobuf (3.0.0.alpha.5.0.5.1)
@@ -48,32 +48,28 @@ RSpec.describe "bundle install with specific platforms" do
L
# force strict usage of the lock file by setting frozen mode
- bundle "config set --local frozen true", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local frozen true", :env => { "BUNDLER_VERSION" => "2.1.4" }
# make sure the platform that got actually installed with the old bundler is used
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
end
end
- it "understands that a non-platform specific gem in a new lockfile locked only to ruby doesn't necessarily mean installing the non-specific variant" do
+ it "understands that a non-platform specific gem in a new lockfile locked only to RUBY doesn't necessarily mean installing the non-specific variant" do
simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
system_gems "bundler-2.1.4"
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
gemfile google_protobuf
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "google-protobuf", "3.0.0.alpha.4.0"
- end
-
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
google-protobuf (3.0.0.alpha.4.0)
@@ -82,14 +78,12 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
google-protobuf
- #{checksums}
+
BUNDLED WITH
2.1.4
L
- bundle "update", env: { "BUNDLER_VERSION" => Bundler::VERSION }
-
- checksums.checksum gem_repo2, "google-protobuf", "3.0.0.alpha.5.0.5.1"
+ bundle "update", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
# make sure the platform that the platform specific dependency is used, since we're only locked to ruby
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
@@ -97,7 +91,7 @@ RSpec.describe "bundle install with specific platforms" do
# make sure we're still only locked to ruby
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
google-protobuf (3.0.0.alpha.5.0.5.1)
@@ -106,14 +100,14 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
google-protobuf
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
end
- context "when running on a legacy lockfile locked only to ruby" do
+ context "when running on a legacy lockfile locked only to RUBY" do
around do |example|
build_repo4 do
build_gem "nokogiri", "1.3.10"
@@ -121,17 +115,19 @@ RSpec.describe "bundle install with specific platforms" do
s.platform = "arm64-darwin"
s.required_ruby_version = "< #{Gem.ruby_version}"
end
+
+ build_gem "bundler", "2.1.4"
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
G
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.3.10)
@@ -141,21 +137,22 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri
+ RUBY VERSION
+ 2.5.3p105
+
BUNDLED WITH
- #{Bundler::VERSION}
+ 2.1.4
L
simulate_platform "arm64-darwin-22", &example
end
- it "still installs the generic ruby variant if necessary" do
- bundle "install --verbose"
- expect(out).to include("Installing nokogiri 1.3.10")
+ it "still installs the generic RUBY variant if necessary" do
+ bundle "update --bundler", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end
- it "still installs the generic ruby variant if necessary, even in frozen mode" do
- bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" }
- expect(out).to include("Installing nokogiri 1.3.10")
+ it "still installs the generic RUBY variant if necessary, even in frozen mode" do
+ bundle "update --bundler", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "BUNDLE_FROZEN" => "true" }
end
end
@@ -166,24 +163,24 @@ RSpec.describe "bundle install with specific platforms" do
build_gem("libv8", "8.4.255.0") {|s| s.platform = "universal-darwin" }
build_gem("mini_racer", "1.0.0") do |s|
- s.add_dependency "libv8"
+ s.add_runtime_dependency "libv8"
end
end
system_gems "bundler-2.1.4"
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
gemfile <<-G
- source "https://gem.repo2"
+ source "https://localgemserver.test"
gem "libv8"
G
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: https://localgemserver.test/
specs:
libv8 (8.4.255.0)
@@ -197,10 +194,10 @@ RSpec.describe "bundle install with specific platforms" do
2.1.4
L
- bundle "install --verbose", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_VERSION" => "2.1.4", "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Installing libv8 8.4.255.0 (universal-darwin)")
- bundle "add mini_racer --verbose"
+ bundle "add mini_racer --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Using libv8 8.4.255.0 (universal-darwin)")
end
end
@@ -213,14 +210,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
gem "grpc"
G
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
grpc (1.50.0)
@@ -234,7 +231,7 @@ RSpec.describe "bundle install with specific platforms" do
#{Bundler::VERSION}
L
- bundle "install --verbose", artifice: "compact_index_precompiled_before"
+ bundle "install --verbose", :artifice => "compact_index_precompiled_before", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(out).to include("Installing grpc 1.50.0 (universal-darwin)")
end
end
@@ -268,7 +265,7 @@ RSpec.describe "bundle install with specific platforms" do
git = build_git "pg_array_parser", "1.0"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "pg_array_parser", :git => "#{lib_path("pg_array_parser-1.0")}"
G
@@ -304,15 +301,15 @@ RSpec.describe "bundle install with specific platforms" do
simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem_with_different_dependencies_per_platform
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "facter"
G
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- expect(the_bundle.locked_gems.platforms).to include(pl("x86_64-darwin-15"))
+ expect(the_bundle.locked_gems.platforms).to eq([pl("x86_64-darwin-15")])
expect(the_bundle).to include_gems("facter 2.4.6 universal-darwin", "CFPropertyList 1.0")
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to include("CFPropertyList-1.0",
- "facter-2.4.6-universal-darwin")
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(["CFPropertyList-1.0",
+ "facter-2.4.6-universal-darwin"])
end
end
@@ -327,8 +324,8 @@ RSpec.describe "bundle install with specific platforms" do
install_gemfile(google_protobuf)
bundle "lock --add-platform=#{x64_mingw32}"
- expect(the_bundle.locked_gems.platforms).to include(x64_mingw32, pl("x86_64-darwin-15"))
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(*%w[
+ expect(the_bundle.locked_gems.platforms).to eq([x64_mingw32, pl("x86_64-darwin-15")])
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[
google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw32
])
@@ -341,11 +338,11 @@ RSpec.describe "bundle install with specific platforms" do
install_gemfile(google_protobuf)
bundle "lock --add-platform=#{java}"
- expect(the_bundle.locked_gems.platforms).to include(java, pl("x86_64-darwin-15"))
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(
- "google-protobuf-3.0.0.alpha.5.0.5.1",
- "google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin"
- )
+ expect(the_bundle.locked_gems.platforms).to eq([java, pl("x86_64-darwin-15")])
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[
+ google-protobuf-3.0.0.alpha.5.0.5.1
+ google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
+ ])
end
end
end
@@ -358,14 +355,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "sorbet-static", "0.5.6403"
G
lockfile <<~L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
sorbet-static (0.5.6403-#{Bundler.local_platform})
@@ -389,13 +386,13 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static", "0.5.6433"
G
error_message = <<~ERROR.strip
- Could not find gem 'sorbet-static (= 0.5.6433)' with platform 'arm64-darwin-21' in rubygems repository https://gem.repo4/ or installed locally.
+ Could not find gem 'sorbet-static (= 0.5.6433)' with platform 'arm64-darwin-21' in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
The source contains the following gems matching 'sorbet-static (= 0.5.6433)':
* sorbet-static-0.5.6433-universal-darwin-20
@@ -403,7 +400,7 @@ RSpec.describe "bundle install with specific platforms" do
ERROR
simulate_platform "arm64-darwin-21" do
- bundle "lock", raise_on_error: false
+ bundle "lock", :raise_on_error => false
end
expect(err).to include(error_message).once
@@ -411,7 +408,7 @@ RSpec.describe "bundle install with specific platforms" do
# Make sure it doesn't print error twice in verbose mode
simulate_platform "arm64-darwin-21" do
- bundle "lock --verbose", raise_on_error: false
+ bundle "lock --verbose", :raise_on_error => false
end
expect(err).to include(error_message).once
@@ -425,7 +422,7 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet", "0.5.6433"
G
@@ -434,8 +431,8 @@ RSpec.describe "bundle install with specific platforms" do
Could not find compatible versions
Because every version of sorbet depends on sorbet-static = 0.5.6433
- and sorbet-static = 0.5.6433 could not be found in rubygems repository https://gem.repo4/ or installed locally for any resolution platforms (arm64-darwin-21),
- sorbet cannot be used.
+ and sorbet-static = 0.5.6433 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally for any resolution platforms (arm64-darwin-21),
+ every version of sorbet is forbidden.
So, because Gemfile depends on sorbet = 0.5.6433,
version solving has failed.
@@ -445,7 +442,7 @@ RSpec.describe "bundle install with specific platforms" do
ERROR
simulate_platform "arm64-darwin-21" do
- bundle "lock", raise_on_error: false
+ bundle "lock", :raise_on_error => false
end
expect(err).to include(error_message).once
@@ -453,42 +450,42 @@ RSpec.describe "bundle install with specific platforms" do
# Make sure it doesn't print error twice in verbose mode
simulate_platform "arm64-darwin-21" do
- bundle "lock --verbose", raise_on_error: false
+ bundle "lock --verbose", :raise_on_error => false
end
expect(err).to include(error_message).once
end
- it "does not generate a lockfile if ruby platform is forced and some gem has no ruby variant available" do
+ it "does not generate a lockfile if RUBY platform is forced and some gem has no RUBY variant available" do
build_repo4 do
build_gem("sorbet-static", "0.5.9889") {|s| s.platform = Gem::Platform.local }
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static", "0.5.9889"
G
- bundle "lock", raise_on_error: false, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
+ bundle "lock", :raise_on_error => false, :env => { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
expect(err).to include <<~ERROR.rstrip
- Could not find gem 'sorbet-static (= 0.5.9889)' with platform 'ruby' in rubygems repository https://gem.repo4/ or installed locally.
+ Could not find gem 'sorbet-static (= 0.5.9889)' with platform 'ruby' in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
The source contains the following gems matching 'sorbet-static (= 0.5.9889)':
* sorbet-static-0.5.9889-#{Gem::Platform.local}
ERROR
end
- it "automatically fixes the lockfile if ruby platform is locked and some gem has no ruby variant available" do
+ it "automatically fixes the lockfile if RUBY platform is locked and some gem has no RUBY variant available" do
build_repo4 do
build_gem("sorbet-static-and-runtime", "0.5.10160") do |s|
- s.add_dependency "sorbet", "= 0.5.10160"
- s.add_dependency "sorbet-runtime", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-runtime", "= 0.5.10160"
end
build_gem("sorbet", "0.5.10160") do |s|
- s.add_dependency "sorbet-static", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-static", "= 0.5.10160"
end
build_gem("sorbet-runtime", "0.5.10160")
@@ -499,14 +496,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static-and-runtime"
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10160)
sorbet-static (= 0.5.10160)
@@ -517,7 +514,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-runtime (= 0.5.10160)
PLATFORMS
- #{lockfile_platforms}
+ #{lockfile_platforms_for([specific_local_platform, "ruby"])}
DEPENDENCIES
sorbet-static-and-runtime
@@ -528,16 +525,9 @@ RSpec.describe "bundle install with specific platforms" do
bundle "update"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "sorbet", "0.5.10160"
- c.checksum gem_repo4, "sorbet-runtime", "0.5.10160"
- c.checksum gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
- c.checksum gem_repo4, "sorbet-static-and-runtime", "0.5.10160"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10160)
sorbet-static (= 0.5.10160)
@@ -548,17 +538,17 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-runtime (= 0.5.10160)
PLATFORMS
- #{local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
sorbet-static-and-runtime
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "automatically fixes the lockfile if both ruby platform and a more specific platform are locked, and some gem has no ruby variant available" do
+ it "automatically fixes the lockfile if both RUBY platform and a more specific platform are locked, and some gem has no RUBY variant available" do
build_repo4 do
build_gem "nokogiri", "1.12.0"
build_gem "nokogiri", "1.12.0" do |s|
@@ -577,21 +567,16 @@ RSpec.describe "bundle install with specific platforms" do
simulate_platform "x86_64-darwin-22" do
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
gem "sorbet-static"
G
end
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.13.0", "x86_64-darwin"
- c.checksum gem_repo4, "sorbet-static", "0.5.10601", "x86_64-darwin"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.12.0)
nokogiri (1.12.0-x86_64-darwin)
@@ -603,8 +588,8 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri
- sorbet-static
- #{checksums}
+ sorbet
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -615,7 +600,7 @@ RSpec.describe "bundle install with specific platforms" do
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.13.0-x86_64-darwin)
sorbet-static (0.5.10601-x86_64-darwin)
@@ -626,21 +611,21 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri
sorbet-static
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "automatically fixes the lockfile if only ruby platform is locked and some gem has no ruby variant available" do
+ it "automatically fixes the lockfile if only RUBY platform is locked and some gem has no RUBY variant available" do
build_repo4 do
build_gem("sorbet-static-and-runtime", "0.5.10160") do |s|
- s.add_dependency "sorbet", "= 0.5.10160"
- s.add_dependency "sorbet-runtime", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-runtime", "= 0.5.10160"
end
build_gem("sorbet", "0.5.10160") do |s|
- s.add_dependency "sorbet-static", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-static", "= 0.5.10160"
end
build_gem("sorbet-runtime", "0.5.10160")
@@ -651,14 +636,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static-and-runtime"
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10160)
sorbet-static (= 0.5.10160)
@@ -680,16 +665,9 @@ RSpec.describe "bundle install with specific platforms" do
bundle "update"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "sorbet", "0.5.10160"
- c.checksum gem_repo4, "sorbet-runtime", "0.5.10160"
- c.checksum gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
- c.checksum gem_repo4, "sorbet-static-and-runtime", "0.5.10160"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10160)
sorbet-static (= 0.5.10160)
@@ -700,86 +678,16 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-runtime (= 0.5.10160)
PLATFORMS
- #{local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
sorbet-static-and-runtime
- #{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 "https://gem.repo4"
-
- gem "nokogiri"
- gem "sorbet-static"
- G
-
- lockfile <<~L
- GEM
- remote: https://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
- aarch64-linux
- arm-linux
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- sorbet-static
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "update"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.14.0", "x86_64-linux"
- c.checksum gem_repo4, "sorbet-static", "0.5.10696", "x86_64-linux"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://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}
- 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
@@ -794,20 +702,15 @@ RSpec.describe "bundle install with specific platforms" do
# Make sure sorbet-static-0.5.10549-universal-darwin-21 is installed
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static", "= 0.5.10549"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-20"
- c.checksum gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-21"
- end
-
# Make sure the lockfile is missing sorbet-static-0.5.10549-universal-darwin-21
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet-static (0.5.10549-universal-darwin-20)
@@ -816,7 +719,7 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
sorbet-static (= 0.5.10549)
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -825,7 +728,7 @@ RSpec.describe "bundle install with specific platforms" do
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet-static (0.5.10549-universal-darwin-20)
sorbet-static (0.5.10549-universal-darwin-21)
@@ -835,63 +738,6 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
sorbet-static (= 0.5.10549)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "automatically fixes the lockfile if locked only to ruby, and some locked specs don't meed locked dependencies" do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem("ibandit", "0.7.0") do |s|
- s.add_dependency "i18n", "~> 0.7.0"
- end
-
- build_gem("i18n", "0.7.0.beta1")
- build_gem("i18n", "0.7.0")
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "ibandit", "~> 0.7.0"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- i18n (0.7.0.beta1)
- ibandit (0.7.0)
- i18n (~> 0.7.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- ibandit (~> 0.7.0)
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock --update i18n"
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- i18n (0.7.0)
- ibandit (0.7.0)
- i18n (~> 0.7.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- ibandit (~> 0.7.0)
BUNDLED WITH
#{Bundler::VERSION}
@@ -908,149 +754,45 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
gem "tzinfo", "~> 1.2", platform: :#{not_local_tag}
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.13.8"
- c.checksum gem_repo4, "nokogiri", "1.13.8", Gem::Platform.local
- end
-
original_lockfile = <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.13.8)
nokogiri (1.13.8-#{Gem::Platform.local})
PLATFORMS
- #{lockfile_platforms("ruby")}
+ #{lockfile_platforms_for([specific_local_platform, "ruby"])}
DEPENDENCIES
nokogiri
tzinfo (~> 1.2)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- lockfile original_lockfile
-
- bundle "lock --update"
-
- expect(lockfile).to eq(original_lockfile)
- end
-
- it "does not remove ruby if gems for other platforms, and not present in the lockfile, exist in the Gemfile, and the lockfile only has ruby" do
- build_repo4 do
- build_gem "nokogiri", "1.13.8"
- build_gem "nokogiri", "1.13.8" do |s|
- s.platform = "arm64-darwin"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
- gem "nokogiri"
-
- gem "tzinfo", "~> 1.2", platforms: %i[mingw mswin x64_mingw jruby]
- G
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.13.8"
- end
-
- original_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.13.8)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- nokogiri
- tzinfo (~> 1.2)
- #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
lockfile original_lockfile
- simulate_platform "arm64-darwin-23" do
- bundle "lock --update"
- end
+ bundle "lock --update"
expect(lockfile).to eq(original_lockfile)
end
- it "does not remove ruby when adding a new gem to the Gemfile" do
- build_repo4 do
- build_gem "concurrent-ruby", "1.2.2"
- build_gem "myrack", "3.0.7"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "concurrent-ruby"
- gem "myrack"
- G
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "concurrent-ruby", "1.2.2"
- c.checksum gem_repo4, "myrack", "3.0.7"
- end
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- concurrent-ruby (1.2.2)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- concurrent-ruby
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock"
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- concurrent-ruby (1.2.2)
- myrack (3.0.7)
-
- PLATFORMS
- #{lockfile_platforms("ruby", generic_local_platform, defaults: [])}
-
- DEPENDENCIES
- concurrent-ruby
- myrack
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
it "can fallback to a source gem when platform gems are incompatible with current ruby version" do
setup_multiplatform_gem_with_source_gem
+ source = file_uri_for(gem_repo2)
+
gemfile <<~G
- source "https://gem.repo2"
+ source "#{source}"
gem "my-precompiled-gem"
G
@@ -1060,7 +802,7 @@ RSpec.describe "bundle install with specific platforms" do
# - A source gem with compatible ruby version
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{source}/
specs:
my-precompiled-gem (3.0.0)
my-precompiled-gem (3.0.0-#{Bundler.local_platform})
@@ -1096,18 +838,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri", "1.14.0"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.14.0", "x86_64-linux"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.14.0-x86_64-linux)
@@ -1116,20 +854,16 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri (= 1.14.0)
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
bundle :install
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.14.0"
- end
-
expect(lockfile).to eq(<<~L)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.14.0)
@@ -1138,525 +872,13 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri (= 1.14.0)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "automatically fixes the lockfile when only ruby platform locked, and adding a dependency with subdependencies not valid for ruby" do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem("sorbet", "0.5.10160") do |s|
- s.add_dependency "sorbet-static", "= 0.5.10160"
- end
-
- build_gem("sorbet-static", "0.5.10160") do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "sorbet"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock"
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- sorbet (0.5.10160)
- sorbet-static (= 0.5.10160)
- sorbet-static (0.5.10160-x86_64-linux)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- sorbet
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "locks specific platforms automatically" do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem "nokogiri", "1.14.0"
- 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 "nokogiri", "1.14.0" do |s|
- s.platform = "x64-mingw32"
- end
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "java"
- end
-
- build_gem "sorbet-static", "0.5.10696" do |s|
- s.platform = "x86_64-linux"
- end
- build_gem "sorbet-static", "0.5.10696" do |s|
- s.platform = "universal-darwin-22"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- G
-
- bundle "lock"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.14.0"
- c.checksum gem_repo4, "nokogiri", "1.14.0", "arm-linux"
- c.checksum gem_repo4, "nokogiri", "1.14.0", "x86_64-linux"
- end
-
- # locks all compatible platforms, excluding Java and Windows
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.0)
- nokogiri (1.14.0-arm-linux)
- nokogiri (1.14.0-x86_64-linux)
-
- PLATFORMS
- arm-linux
- ruby
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- gem "sorbet-static"
- G
-
- FileUtils.rm bundled_app_lock
-
- bundle "lock"
-
- checksums.delete "nokogiri", "arm-linux"
- checksums.checksum gem_repo4, "sorbet-static", "0.5.10696", "universal-darwin-22"
- checksums.checksum gem_repo4, "sorbet-static", "0.5.10696", "x86_64-linux"
-
- # locks only platforms compatible with all gems in the bundle
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.0)
- nokogiri (1.14.0-x86_64-linux)
- sorbet-static (0.5.10696-universal-darwin-22)
- sorbet-static (0.5.10696-x86_64-linux)
-
- PLATFORMS
- universal-darwin-22
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- sorbet-static
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "does not fail when a platform variant is incompatible with the current ruby and another equivalent platform specific variant is part of the resolution", rubygems: ">= 3.3.21" do
- build_repo4 do
- build_gem "nokogiri", "1.15.5"
-
- build_gem "nokogiri", "1.15.5" do |s|
- s.platform = "x86_64-linux"
- s.required_ruby_version = "< #{current_ruby_minor}.dev"
- end
-
- build_gem "sass-embedded", "1.69.5"
-
- build_gem "sass-embedded", "1.69.5" do |s|
- s.platform = "x86_64-linux-gnu"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- gem "sass-embedded"
- G
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.15.5"
- c.checksum gem_repo4, "sass-embedded", "1.69.5"
- c.checksum gem_repo4, "sass-embedded", "1.69.5", "x86_64-linux-gnu"
- end
-
- simulate_platform "x86_64-linux" do
- bundle "install --verbose"
-
- # locks all compatible platforms, excluding Java and Windows
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.15.5)
- sass-embedded (1.69.5)
- sass-embedded (1.69.5-x86_64-linux-gnu)
-
- PLATFORMS
- ruby
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- sass-embedded
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "does not add ruby platform gem if it brings extra dependencies not resolved originally" do
- build_repo4 do
- build_gem "nokogiri", "1.15.5" do |s|
- s.add_dependency "mini_portile2", "~> 2.8.2"
- end
-
- build_gem "nokogiri", "1.15.5" do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- G
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.15.5", "x86_64-linux"
- end
-
- simulate_platform "x86_64-linux" do
- bundle "install --verbose"
-
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.15.5-x86_64-linux)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- ["x86_64-linux", "x86_64-linux-musl"].each do |host_platform|
- describe "on host platform #{host_platform}" do
- it "adds current musl platform" do
- build_repo4 do
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "x86_64-linux-musl"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "rcee_precompiled", "0.5.0"
- G
-
- simulate_platform host_platform do
- bundle "lock"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "x86_64-linux"
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "x86_64-linux-musl"
- end
-
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- rcee_precompiled (0.5.0-x86_64-linux)
- rcee_precompiled (0.5.0-x86_64-linux-musl)
-
- PLATFORMS
- x86_64-linux
- x86_64-linux-musl
-
- DEPENDENCIES
- rcee_precompiled (= 0.5.0)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
- end
- end
-
- it "adds current musl platform, when there are also gnu variants", rubygems: ">= 3.3.21" do
- build_repo4 do
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "x86_64-linux-gnu"
- end
-
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "x86_64-linux-musl"
- end
- end
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "rcee_precompiled", "0.5.0"
- G
-
- simulate_platform "x86_64-linux-musl" do
- bundle "lock"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "x86_64-linux-gnu"
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "x86_64-linux-musl"
- end
-
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- rcee_precompiled (0.5.0-x86_64-linux-gnu)
- rcee_precompiled (0.5.0-x86_64-linux-musl)
-
- PLATFORMS
- x86_64-linux-gnu
- x86_64-linux-musl
-
- DEPENDENCIES
- rcee_precompiled (= 0.5.0)
- #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
end
- it "does not add current platform if there's an equivalent less specific platform among the ones resolved" do
- build_repo4 do
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "universal-darwin"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "rcee_precompiled", "0.5.0"
- G
-
- simulate_platform "x86_64-darwin-15" do
- bundle "lock"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "universal-darwin"
- end
-
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- rcee_precompiled (0.5.0-universal-darwin)
-
- PLATFORMS
- universal-darwin
-
- DEPENDENCIES
- rcee_precompiled (= 0.5.0)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "does not re-resolve when a specific platform, but less specific than the current platform, is locked" do
- build_repo4 do
- build_gem "nokogiri"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.0)
-
- PLATFORMS
- arm64-darwin
-
- DEPENDENCIES
- nokogiri!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- simulate_platform "arm64-darwin-23" do
- bundle "install --verbose"
-
- expect(out).to include("Found no changes, using resolution from the lockfile")
- end
- end
-
- it "does not remove generic platform gems locked for a specific platform from lockfile when unlocking an unrelated gem" do
- build_repo4 do
- build_gem "ffi"
-
- build_gem "ffi" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "nokogiri"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "ffi"
- gem "nokogiri"
- G
-
- original_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- ffi (1.0)
- nokogiri (1.0)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- ffi
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- lockfile original_lockfile
-
- simulate_platform "x86_64-linux" do
- bundle "lock --update nokogiri"
-
- expect(lockfile).to eq(original_lockfile)
- end
- end
-
- it "does not remove generic platform gems locked for a specific platform from lockfile when unlocking an unrelated gem, and variants for other platform also locked" do
- build_repo4 do
- build_gem "ffi"
-
- build_gem "ffi" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "ffi" do |s|
- s.platform = "java"
- end
-
- build_gem "nokogiri"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "ffi"
- gem "nokogiri"
- G
-
- original_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- ffi (1.0)
- ffi (1.0-java)
- nokogiri (1.0)
-
- PLATFORMS
- java
- x86_64-linux
-
- DEPENDENCIES
- ffi
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- lockfile original_lockfile
-
- simulate_platform "x86_64-linux" do
- bundle "lock --update nokogiri"
-
- expect(lockfile).to eq(original_lockfile)
- end
- end
-
private
def setup_multiplatform_gem
@@ -1682,7 +904,7 @@ RSpec.describe "bundle install with specific platforms" do
build_gem("facter", "2.4.6")
build_gem("facter", "2.4.6") do |s|
s.platform = "universal-darwin"
- s.add_dependency "CFPropertyList"
+ s.add_runtime_dependency "CFPropertyList"
end
build_gem("CFPropertyList")
end
diff --git a/spec/bundler/install/gemfile_spec.rb b/spec/bundler/install/gemfile_spec.rb
index 96ed174e9b..e643573454 100644
--- a/spec/bundler/install/gemfile_spec.rb
+++ b/spec/bundler/install/gemfile_spec.rb
@@ -3,8 +3,8 @@
RSpec.describe "bundle install" do
context "with duplicated gems" do
it "will display a warning" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem 'rails', '~> 4.0.0'
gem 'rails', '~> 4.0.0'
@@ -16,24 +16,24 @@ RSpec.describe "bundle install" do
context "with --gemfile" do
it "finds the gemfile" do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- bundle :install, gemfile: bundled_app("NotGemfile")
+ bundle :install, :gemfile => bundled_app("NotGemfile")
# Specify BUNDLE_GEMFILE for `the_bundle`
# to retrieve the proper Gemfile
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
context "with gemfile set via config" do
before do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
@@ -42,59 +42,34 @@ RSpec.describe "bundle install" do
bundle "install"
bundle "list"
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
it "uses the gemfile while in a subdirectory" do
bundled_app("subdir").mkpath
- bundle "install", dir: bundled_app("subdir")
- bundle "list", dir: bundled_app("subdir")
+ bundle "install", :dir => bundled_app("subdir")
+ bundle "list", :dir => bundled_app("subdir")
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
end
context "with deprecated features" do
it "reports that lib is an invalid option" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", :lib => "myrack"
+ gem "rack", :lib => "rack"
G
- bundle :install, raise_on_error: false
- expect(err).to match(/You passed :lib as an option for gem 'myrack', but it is invalid/)
- end
- end
-
- context "when an internal error happens" do
- let(:bundler_bug) do
- create_file("bundler_bug.rb", <<~RUBY)
- require "bundler"
-
- module Bundler
- class Dsl
- def source(source, *args, &blk)
- nil.name
- end
- end
- end
- RUBY
-
- bundled_app("bundler_bug.rb").to_s
- end
-
- it "shows culprit file and line" do
- skip "ruby-core test setup has always \"lib\" in $LOAD_PATH so `require \"bundler\"` always activates the local version rather than using RubyGems gem activation stuff, causing conflicts" if ruby_core?
-
- install_gemfile "source 'https://gem.repo1'", requires: [bundler_bug], artifice: nil, raise_on_error: false
- expect(err).to include("bundler_bug.rb:6")
+ bundle :install, :raise_on_error => false
+ expect(err).to match(/You passed :lib as an option for gem 'rack', but it is invalid/)
end
end
context "with engine specified in symbol", :jruby_only do
it "does not raise any error parsing Gemfile" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{RUBY_VERSION}", :engine => :jruby, :engine_version => "#{RUBY_ENGINE_VERSION}"
G
@@ -103,19 +78,19 @@ RSpec.describe "bundle install" do
it "installation succeeds" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{RUBY_VERSION}", :engine => :jruby, :engine_version => "#{RUBY_ENGINE_VERSION}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
context "with a Gemfile containing non-US-ASCII characters" do
it "reads the Gemfile with the UTF-8 encoding by default" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
str = "Il était une fois ..."
puts "The source encoding is: " + str.encoding.name
@@ -130,7 +105,7 @@ RSpec.describe "bundle install" do
# NOTE: This works thanks to #eval interpreting the magic encoding comment
install_gemfile <<-G
# encoding: iso-8859-1
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
str = "Il #{"\xE9".dup.force_encoding("binary")}tait une fois ..."
puts "The source encoding is: " + str.encoding.name
diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb
index 4653ce6d87..b6c361186a 100644
--- a/spec/bundler/install/gems/compact_index_spec.rb
+++ b/spec/bundler/install/gems/compact_index_spec.rb
@@ -7,27 +7,12 @@ RSpec.describe "compact index api" do
it "should use the API" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "has a debug mode" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle :install, artifice: "compact_index", env: { "DEBUG_COMPACT_INDEX" => "true" }
- expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(err).to include("[Bundler::CompactIndexClient] available?")
- expect(err).to include("[Bundler::CompactIndexClient] fetching versions")
- expect(err).to include("[Bundler::CompactIndexClient] info(myrack)")
- expect(err).to include("[Bundler::CompactIndexClient] fetching info/myrack")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should URI encode gem names" do
@@ -36,7 +21,7 @@ RSpec.describe "compact index api" do
gem " sinatra"
G
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("' sinatra' is not a valid gem name because it contains whitespace.")
end
@@ -46,7 +31,7 @@ RSpec.describe "compact index api" do
gem "rails"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems(
"rails 2.3.2",
@@ -59,23 +44,23 @@ RSpec.describe "compact index api" do
end
it "should handle case sensitivity conflicts" do
- build_repo4(build_compact_index: false) do
- build_gem "myrack", "1.0" do |s|
- s.add_dependency("Myrack", "0.1")
+ build_repo4 do
+ build_gem "rack", "1.0" do |s|
+ s.add_runtime_dependency("Rack", "0.1")
end
- build_gem "Myrack", "0.1"
+ build_gem "Rack", "0.1"
end
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
source "#{source_uri}"
- gem "myrack", "1.0"
- gem "Myrack", "0.1"
+ gem "rack", "1.0"
+ gem "Rack", "0.1"
G
# can't use `include_gems` here since the `require` will conflict on a
# case-insensitive FS
- run "Bundler.require; puts Gem.loaded_specs.values_at('myrack', 'Myrack').map(&:full_name)"
- expect(out).to eq("myrack-1.0\nMyrack-0.1")
+ run "Bundler.require; puts Gem.loaded_specs.values_at('rack', 'Rack').map(&:full_name)"
+ expect(out).to eq("rack-1.0\nRack-0.1")
end
it "should handle multiple gem dependencies on the same gem" do
@@ -84,22 +69,22 @@ RSpec.describe "compact index api" do
gem "net-sftp"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(the_bundle).to include_gems "net-sftp 1.1.1"
end
it "should use the endpoint when using deployment mode" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "handles git dependencies that are in rubygems" do
@@ -110,12 +95,12 @@ RSpec.describe "compact index api" do
gemfile <<-G
source "#{source_uri}"
- git "#{lib_path("foo-1.0")}" do
+ git "#{file_uri_for(lib_path("foo-1.0"))}" do
gem 'foo'
end
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -128,13 +113,13 @@ RSpec.describe "compact index api" do
gemfile <<-G
source "#{source_uri}"
- gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
bundle "config set --local deployment true"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -143,12 +128,12 @@ RSpec.describe "compact index api" do
build_git "foo"
gemfile <<-G
source "#{source_uri}"
- gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle "install", artifice: "compact_index"
+ bundle "install", :artifice => "compact_index"
bundle "config set --local deployment true"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(the_bundle).to include_gems("foo 1.0")
end
@@ -156,42 +141,41 @@ RSpec.describe "compact index api" do
it "falls back when the API URL returns 403 Forbidden" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "compact_index_forbidden"
+ bundle :install, :verbose => true, :artifice => "compact_index_forbidden"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "falls back when the versions endpoint has a checksum mismatch" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "compact_index_checksum_mismatch"
+ bundle :install, :verbose => true, :artifice => "compact_index_checksum_mismatch"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(out).to include("The checksum of /versions does not match the checksum provided by the server!")
- expect(out).to include("Calculated checksums #{{ "sha-256" => "8KfZiM/fszVkqhP/m5s9lvE6M9xKu4I1bU4Izddp5Ms=" }.inspect} did not match expected #{{ "sha-256" => "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=" }.inspect}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(out).to include <<-'WARN'
+The checksum of /versions does not match the checksum provided by the server! Something is wrong (local checksum is "\"d41d8cd98f00b204e9800998ecf8427e\"", was expecting "\"123\"").
+ WARN
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "shows proper path when permission errors happen", :permissions do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- versions = Pathname.new(Bundler.rubygems.user_home).join(
- ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
- )
- versions.dirname.mkpath
- versions.write("created_at")
+ versions = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions")
+ FileUtils.mkdir_p(File.dirname(versions))
+ FileUtils.touch(versions)
FileUtils.chmod("-r", versions)
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include(
"There was an error while trying to read from `#{versions}`. It is likely that you need to grant read permissions for that path."
@@ -203,28 +187,28 @@ RSpec.describe "compact index api" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "handles host redirects" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_host_redirect"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_host_redirect"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "handles host redirects without Gem::Net::HTTP::Persistent" do
+ it "handles host redirects without Net::HTTP::Persistent" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
FileUtils.mkdir_p lib_path
@@ -240,18 +224,18 @@ RSpec.describe "compact index api" do
H
end
- bundle :install, artifice: "compact_index_host_redirect", requires: [lib_path("disable_net_http_persistent.rb")]
+ bundle :install, :artifice => "compact_index_host_redirect", :requires => [lib_path("disable_net_http_persistent.rb")]
expect(out).to_not match(/Too many redirects/)
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "times out when Bundler::Fetcher redirects too much" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_redirects", raise_on_error: false
+ bundle :install, :artifice => "compact_index_redirects", :raise_on_error => false
expect(err).to match(/Too many redirects/)
end
@@ -259,23 +243,23 @@ RSpec.describe "compact index api" do
it "should use the modern index for install" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --full-index", artifice: "compact_index"
+ bundle "install --full-index", :artifice => "compact_index"
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should use the modern index for update" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "update --full-index", artifice: "compact_index", all: true
+ bundle "update --full-index", :artifice => "compact_index", :all => true
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -303,22 +287,22 @@ RSpec.describe "compact index api" do
end
end
- system_gems %w[myrack-1.0.0 thin-1.0 net_a-1.0], gem_repo: gem_repo2
+ 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/myrack
+ #{source_uri}/info/rack
EOS
- install_gemfile <<-G, artifice: "compact_index", verbose: true, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ install_gemfile <<-G, :artifice => "compact_index", :verbose => true, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
expect(last_command.stdboth).not_to include "Double checking"
end
- it "fetches again when more dependencies are found in subsequent sources", bundler: "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -332,7 +316,7 @@ RSpec.describe "compact index api" do
gem "back_deps"
G
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
end
@@ -344,7 +328,7 @@ RSpec.describe "compact index api" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "compact_index_extra", verbose: true
+ install_gemfile <<-G, :artifice => "compact_index_extra", :verbose => true
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -357,27 +341,27 @@ RSpec.describe "compact index api" do
it "fetches gem versions even when those gems are already installed" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
- bundle :install, artifice: "compact_index_extra_api"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_extra_api"
+ expect(the_bundle).to include_gems "rack 1.0.0"
build_repo4 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
gemfile <<-G
source "#{source_uri}" do; end
source "#{source_uri}/extra"
- gem "myrack", "1.2"
+ gem "rack", "1.2"
G
- bundle :install, artifice: "compact_index_extra_api"
- expect(the_bundle).to include_gems "myrack 1.2"
+ bundle :install, :artifice => "compact_index_extra_api"
+ expect(the_bundle).to include_gems "rack 1.2"
end
- it "considers all possible versions of dependencies from all api gem sources", bundler: "< 3" do
+ it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 3" do
# In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that
# exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0
# of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other
@@ -395,7 +379,7 @@ RSpec.describe "compact index api" do
gem 'somegem', '1.0.0'
G
- bundle :install, artifice: "compact_index_extra_api"
+ bundle :install, :artifice => "compact_index_extra_api"
expect(the_bundle).to include_gems "somegem 1.0.0"
expect(the_bundle).to include_gems "activesupport 1.2.3"
@@ -416,13 +400,13 @@ RSpec.describe "compact index api" do
end
G
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
expect(out).to include("Fetching gem metadata from http://localgemserver.test/")
expect(out).to include("Fetching source index from http://localgemserver.test/extra")
end
- it "does not fetch every spec when doing back deps" do
+ it "does not fetch every spec if the index of gems is large when doing back deps" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -432,7 +416,9 @@ RSpec.describe "compact index api" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "compact_index_extra_missing"
+ api_request_limit = low_api_request_limit_for(gem_repo2)
+
+ install_gemfile <<-G, :artifice => "compact_index_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation)
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -442,7 +428,7 @@ RSpec.describe "compact index api" do
expect(the_bundle).to include_gems "back_deps 1.0"
end
- it "does not fetch every spec when doing back deps & everything is the compact index" do
+ it "does not fetch every spec if the index of gems is large when doing back deps & everything is the compact index" do
build_repo4 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -452,7 +438,9 @@ RSpec.describe "compact index api" do
FileUtils.rm_rf Dir[gem_repo4("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "compact_index_extra_api_missing"
+ api_request_limit = low_api_request_limit_for(gem_repo4)
+
+ install_gemfile <<-G, :artifice => "compact_index_extra_api_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation)
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -469,11 +457,11 @@ RSpec.describe "compact index api" do
gem 'foo'
G
- bundle :install, artifice: "compact_index_api_missing"
+ bundle :install, :artifice => "compact_index_api_missing"
expect(the_bundle).to include_gems "foo 1.0"
end
- it "fetches again when more dependencies are found in subsequent sources using deployment mode", bundler: "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources using deployment mode", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -487,9 +475,9 @@ RSpec.describe "compact index api" do
gem "back_deps"
G
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
bundle "config --set local deployment true"
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -508,9 +496,9 @@ RSpec.describe "compact index api" do
end
G
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
bundle "config set --local deployment true"
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -527,70 +515,70 @@ RSpec.describe "compact index api" do
gem "bundler_dep"
G
- bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle :install, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "installs the binstubs", bundler: "< 3" do
+ it "installs the binstubs", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --binstubs", artifice: "compact_index"
+ bundle "install --binstubs", :artifice => "compact_index"
- gembin "myrackup"
+ gembin "rackup"
expect(out).to eq("1.0.0")
end
- it "installs the bins when using --path and uses autoclean", bundler: "< 3" do
+ it "installs the bins when using --path and uses autoclean", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --path vendor/bundle", artifice: "compact_index"
+ bundle "install --path vendor/bundle", :artifice => "compact_index"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
- it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do
+ it "installs the bins when using --path and uses bundle clean", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --path vendor/bundle --no-clean", artifice: "compact_index"
+ bundle "install --path vendor/bundle --no-clean", :artifice => "compact_index"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "prints post_install_messages" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack-obama'
+ gem 'rack-obama'
G
- bundle :install, artifice: "compact_index"
- expect(out).to include("Post-install message from myrack:")
+ bundle :install, :artifice => "compact_index"
+ expect(out).to include("Post-install message from rack:")
end
it "should display the post install message for a dependency" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack_middleware'
+ gem 'rack_middleware'
G
- bundle :install, artifice: "compact_index"
- expect(out).to include("Post-install message from myrack:")
- expect(out).to include("Myrack's post install message")
+ bundle :install, :artifice => "compact_index"
+ expect(out).to include("Post-install message from rack:")
+ expect(out).to include("Rack's post install message")
end
context "when using basic authentication" do
let(:user) { "user" }
let(:password) { "pass" }
let(:basic_auth_source_uri) do
- uri = Gem::URI.parse(source_uri)
+ uri = Bundler::URI.parse(source_uri)
uri.user = user
uri.password = password
@@ -600,113 +588,104 @@ RSpec.describe "compact index api" do
it "passes basic authentication details and strips out creds" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_basic_authentication"
+ bundle :install, :artifice => "compact_index_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "passes basic authentication details and strips out creds also in verbose mode" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "compact_index_basic_authentication"
+ bundle :install, :verbose => true, :artifice => "compact_index_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "strips http basic auth creds when warning about ambiguous sources", bundler: "< 3" do
+ it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 3" do
gemfile <<-G
source "#{basic_auth_source_uri}"
source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_basic_authentication"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
+ bundle :install, :artifice => "compact_index_basic_authentication"
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not pass the user / password to different hosts on redirect" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_creds_diff_host"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_creds_diff_host"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
describe "with authentication details in bundle config" do
before do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
end
it "reads authentication details by host name from bundle config" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, artifice: "compact_index_strict_basic_authentication"
+ bundle :install, :artifice => "compact_index_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "reads authentication details by full url from bundle config" do
# The trailing slash is necessary here; Fetcher canonicalizes the URI.
bundle "config set #{source_uri}/ #{user}:#{password}"
- bundle :install, artifice: "compact_index_strict_basic_authentication"
+ bundle :install, :artifice => "compact_index_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should use the API" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, artifice: "compact_index_strict_basic_authentication"
+ bundle :install, :artifice => "compact_index_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "prefers auth supplied in the source uri" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
bundle "config set #{source_hostname} otheruser:wrong"
- bundle :install, artifice: "compact_index_strict_basic_authentication"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_strict_basic_authentication"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "shows instructions if auth is not provided for the source" do
- bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false
+ bundle :install, :artifice => "compact_index_strict_basic_authentication", :raise_on_error => false
expect(err).to include("bundle config set --global #{source_hostname} username:password")
end
it "fails if authentication has already been provided, but failed" do
bundle "config set #{source_hostname} #{user}:wrong"
- bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false
- expect(err).to include("Bad username or password")
- end
-
- it "does not fallback to old dependency API if bad authentication is provided" do
- bundle "config set #{source_hostname} #{user}:wrong"
-
- bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false, verbose: true
+ bundle :install, :artifice => "compact_index_strict_basic_authentication", :raise_on_error => false
expect(err).to include("Bad username or password")
- expect(out).to include("HTTP 401 Unauthorized http://user@localgemserver.test/versions")
- expect(out).not_to include("HTTP 401 Unauthorized http://user@localgemserver.test/api/v1/dependencies")
end
end
@@ -716,11 +695,11 @@ RSpec.describe "compact index api" do
it "passes basic authentication details" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_basic_authentication"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_basic_authentication"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
end
@@ -741,10 +720,10 @@ RSpec.describe "compact index api" do
it "explains what to do to get it" do
gemfile <<-G
source "#{source_uri.gsub(/http/, "https")}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false, artifice: nil
+ bundle :install, :env => { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, :raise_on_error => false
expect(err).to include("OpenSSL")
end
end
@@ -754,17 +733,17 @@ RSpec.describe "compact index api" do
# Install a monkeypatch that reproduces the effects of openssl raising
# a certificate validation error when RubyGems tries to connect.
gemfile <<-G
- class Gem::Net::HTTP
+ class Net::HTTP
def start
raise OpenSSL::SSL::SSLError, "certificate verify failed"
end
end
source "#{source_uri.gsub(/http/, "https")}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to match(/could not verify the SSL certificate/i)
end
end
@@ -772,206 +751,118 @@ RSpec.describe "compact index api" do
context ".gemrc with sources is present" do
it "uses other sources declared in the Gemfile" do
File.open(home(".gemrc"), "w") do |file|
- file.puts({ sources: ["https://rubygems.org"] }.to_yaml)
+ file.puts({ :sources => ["https://rubygems.org"] }.to_yaml)
end
begin
gemfile <<-G
source "#{source_uri}"
- gem 'myrack'
+ gem 'rack'
G
- bundle :install, artifice: "compact_index_forbidden"
+ bundle :install, :artifice => "compact_index_forbidden"
ensure
home(".gemrc").rmtree
end
end
end
- it "performs update with etag not-modified" do
- versions_etag = Pathname.new(Bundler.rubygems.user_home).join(
- ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions.etag"
- )
- expect(versions_etag.file?).to eq(false)
-
+ it "performs partial update with a non-empty range" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack', '0.9.1'
+ gem 'rack', '0.9.1'
G
- # Initial install creates the cached versions file and etag file
- bundle :install, artifice: "compact_index"
-
- expect(versions_etag.file?).to eq(true)
- previous_content = versions_etag.binread
+ # Initial install creates the cached versions file
+ bundle :install, :artifice => "compact_index"
# Update the Gemfile so we can check subsequent install was successful
gemfile <<-G
source "#{source_uri}"
- gem 'myrack', '1.0.0'
+ gem 'rack', '1.0.0'
G
- # Second install should match etag
- bundle :install, artifice: "compact_index_etag_match"
+ # Second install should make only a partial request to /versions
+ bundle :install, :artifice => "compact_index_partial_update"
- expect(versions_etag.binread).to eq(previous_content)
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "performs full update when range is ignored" do
- gemfile <<-G
- source "#{source_uri}"
- gem 'myrack', '0.9.1'
- G
-
- # Initial install creates the cached versions file and etag file
- bundle :install, artifice: "compact_index"
-
- gemfile <<-G
- source "#{source_uri}"
- gem 'myrack', '1.0.0'
- G
-
- versions = Pathname.new(Bundler.rubygems.user_home).join(
- ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
- )
- # Modify the cached file. The ranged request will be based on this but,
- # in this test, the range is ignored so this gets overwritten, allowing install.
- versions.write "ruining this file"
-
- bundle :install, artifice: "compact_index_range_ignored"
-
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "performs partial update with a non-empty range" do
- build_repo4 do
- build_gem "myrack", "0.9.1"
- end
-
- # Initial install creates the cached versions file
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "#{source_uri}"
- gem 'myrack', '0.9.1'
- G
-
- update_repo4 do
- build_gem "myrack", "1.0.0"
- end
-
- install_gemfile <<-G, artifice: "compact_index_partial_update", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "#{source_uri}"
- gem 'myrack', '1.0.0'
- G
-
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "performs partial update while local cache is updated by another process" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack'
- G
-
- # Create a partial cache versions file
- versions = Pathname.new(Bundler.rubygems.user_home).join(
- ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
- )
- versions.dirname.mkpath
- versions.write("created_at")
-
- bundle :install, artifice: "compact_index_concurrent_download"
-
- expect(versions.read).to start_with("created_at")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "performs a partial update that fails digest check, then a full update" do
- build_repo4 do
- build_gem "myrack", "0.9.1"
- end
-
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "#{source_uri}"
- gem 'myrack', '0.9.1'
+ gem 'rack'
G
- update_repo4 do
- build_gem "myrack", "1.0.0"
- end
+ # Create an empty file to trigger a partial download
+ versions = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions")
+ FileUtils.mkdir_p(File.dirname(versions))
+ FileUtils.touch(versions)
- install_gemfile <<-G, artifice: "compact_index_partial_update_bad_digest", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "#{source_uri}"
- gem 'myrack', '1.0.0'
- G
+ bundle :install, :artifice => "compact_index_concurrent_download"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(File.read(versions)).to start_with("created_at")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "performs full update if server endpoints serve partial content responses but don't have incremental content and provide no digest" do
+ it "performs full update if server endpoints serve partial content responses but don't have incremental content and provide no Etag" do
build_repo4 do
- build_gem "myrack", "0.9.1"
+ build_gem "rack", "0.9.1"
end
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
source "#{source_uri}"
- gem 'myrack', '0.9.1'
+ gem 'rack', '0.9.1'
G
update_repo4 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
- install_gemfile <<-G, artifice: "compact_index_partial_update_no_digest_not_incremental", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ install_gemfile <<-G, :artifice => "compact_index_partial_update_no_etag_not_incremental", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
source "#{source_uri}"
- gem 'myrack', '1.0.0'
+ gem 'rack', '1.0.0'
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "performs full update of compact index info cache if range is not satisfiable" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack', '0.9.1'
+ gem 'rack', '0.9.1'
G
- bundle :install, artifice: "compact_index"
+ rake_info_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "info", "rack")
- cache_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5")
+ bundle :install, :artifice => "compact_index"
- # We must remove the etag so that we don't ignore the range and get a 304 Not Modified.
- myrack_info_etag_path = File.join(cache_path, "info-etags", "myrack-92f3313ce5721296f14445c3a6b9c073")
- File.unlink(myrack_info_etag_path) if File.exist?(myrack_info_etag_path)
+ expected_rack_info_content = File.read(rake_info_path)
- myrack_info_path = File.join(cache_path, "info", "myrack")
- expected_myrack_info_content = File.read(myrack_info_path)
-
- # Modify the cache files to make the range not satisfiable
- File.open(myrack_info_path, "a") {|f| f << "0.9.2 |checksum:c55b525b421fd833a93171ad3d7f04528ca8e87d99ac273f8933038942a5888c" }
+ # Modify the cache files. We expect them to be reset to the normal ones when we re-run :install
+ File.open(rake_info_path, "w") {|f| f << (expected_rack_info_content + "this is different") }
# Update the Gemfile so the next install does its normal things
gemfile <<-G
source "#{source_uri}"
- gem 'myrack', '1.0.0'
+ gem 'rack', '1.0.0'
G
# The cache files now being longer means the requested range is going to be not satisfiable
# Bundler must end up requesting the whole file to fix things up.
- bundle :install, artifice: "compact_index_range_not_satisfiable"
+ bundle :install, :artifice => "compact_index_range_not_satisfiable"
- resulting_myrack_info_content = File.read(myrack_info_path)
+ resulting_rack_info_content = File.read(rake_info_path)
- expect(resulting_myrack_info_content).to eq(expected_myrack_info_content)
+ expect(resulting_rack_info_content).to eq(expected_rack_info_content)
end
it "fails gracefully when the source URI has an invalid scheme" do
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
source "htps://rubygems.org"
- gem "myrack"
+ gem "rack"
G
expect(exitstatus).to eq(15)
expect(err).to end_with(<<-E.strip)
@@ -980,96 +871,58 @@ RSpec.describe "compact index api" do
end
describe "checksum validation" do
- before do
- lockfile <<-L
- GEM
- remote: #{source_uri}
- specs:
- myrack (1.0.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- #{checksums_section}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "handles checksums from the server in base64" do
- api_checksum = checksum_digest(gem_repo1, "myrack", "1.0.0")
- myrack_checksum = [[api_checksum].pack("H*")].pack("m0")
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => myrack_checksum }
- source "#{source_uri}"
- gem "myrack"
- G
-
- expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems("myrack 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
+ install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :raise_on_error => false
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- gem_path = if Bundler.feature_flag.global_gem_cache?
- default_cache_path.dirname.join("cache", "gems", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "myrack-1.0.0.gem")
- else
- default_cache_path.dirname.join("myrack-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.
- myrack (1.0.0) sha256=2222222222222222222222222222222222222222222222222222222222222222
- from the API at http://localgemserver.test/
- #{checksum_to_lock(gem_repo1, "myrack", "1.0.0")}
- 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
- install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => "checksum!", "DEBUG" => "1" }, verbose: true, raise_on_error: false
+ install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :env => { "BUNDLER_SPEC_RACK_CHECKSUM" => "checksum!", "DEBUG" => "1" }, :verbose => true, :raise_on_error => false
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- expect(exitstatus).to eq(14)
- expect(err).to include('Invalid checksum for myrack-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
bundle "config set disable_checksum_validation true"
- install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum"
+ install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum"
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
end
end
it "works when cache dir is world-writable" do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
File.umask(0000)
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
end
it "doesn't explode when the API dependencies are wrong" do
- install_gemfile <<-G, artifice: "compact_index_wrong_dependencies", env: { "DEBUG" => "true" }, raise_on_error: false
+ install_gemfile <<-G, :artifice => "compact_index_wrong_dependencies", :env => { "DEBUG" => "true" }, :raise_on_error => false
source "#{source_uri}"
gem "rails"
G
- deps = [Gem::Dependency.new("rake", "= #{rake_version}"),
+ deps = [Gem::Dependency.new("rake", "= 13.0.1"),
Gem::Dependency.new("actionpack", "= 2.3.2"),
Gem::Dependency.new("activerecord", "= 2.3.2"),
Gem::Dependency.new("actionmailer", "= 2.3.2"),
@@ -1077,21 +930,20 @@ RSpec.describe "compact index api" do
expect(out).to include("rails-2.3.2 from rubygems remote at #{source_uri}/ has either corrupted API or lockfile dependencies")
expect(err).to include(<<-E.strip)
Bundler::APIResponseMismatchError: Downloading rails-2.3.2 revealed dependencies not in the API or the lockfile (#{deps.map(&:to_s).join(", ")}).
-Running `bundle update rails` should fix the problem.
+Either installing with `--full-index` or running `bundle update rails` should fix the problem.
E
end
it "does not duplicate specs in the lockfile when updating and a dependency is not installed" do
- install_gemfile <<-G, artifice: "compact_index"
- source "https://gem.repo1"
+ install_gemfile <<-G, :artifice => "compact_index"
+ source "#{file_uri_for(gem_repo1)}"
source "#{source_uri}" do
gem "rails"
gem "activemerchant"
end
G
gem_command "uninstall activemerchant"
- bundle "update rails", artifice: "compact_index"
- count = lockfile.match?("CHECKSUMS") ? 2 : 1 # Once in the specs, and once in CHECKSUMS
- expect(lockfile.scan(/activemerchant \(/).size).to eq(count)
+ bundle "update rails", :artifice => "compact_index"
+ expect(lockfile.scan(/activemerchant \(/).size).to eq(1)
end
end
diff --git a/spec/bundler/install/gems/dependency_api_fallback_spec.rb b/spec/bundler/install/gems/dependency_api_fallback_spec.rb
deleted file mode 100644
index 107da15d67..0000000000
--- a/spec/bundler/install/gems/dependency_api_fallback_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../../support/silent_logger"
-
-RSpec.describe "gemcutter's dependency API" do
- context "when Gemcutter API takes too long to respond" do
- before do
- require_rack
-
- port = find_unused_port
- @server_uri = "http://127.0.0.1:#{port}"
-
- require_relative "../../support/artifice/endpoint_timeout"
-
- # mustermann depends on URI::RFC2396_PARSER behavior
- URI.parser = URI::RFC2396_PARSER if URI.respond_to?(:parser=)
-
- require "rackup/server"
-
- @t = Thread.new do
- server = Rackup::Server.start(app: EndpointTimeout,
- Host: "0.0.0.0",
- Port: port,
- server: "webrick",
- AccessLog: [],
- Logger: Spec::SilentLogger.new)
- server.start
- end
- @t.run
-
- wait_for_server("127.0.0.1", port)
- bundle "config set timeout 1"
- end
-
- after do
- Artifice.deactivate
- @t.kill
- @t.join
-
- URI.parser = URI::DEFAULT_PARSER if URI.respond_to?(:parser=)
- end
-
- it "times out and falls back on the modern index" do
- install_gemfile <<-G, artifice: nil, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
- source "#{@server_uri}"
- gem "myrack"
- G
-
- expect(out).to include("Fetching source index from #{@server_uri}/")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
- end
-end
diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb
index 7396843f1d..6cb3d9697d 100644
--- a/spec/bundler/install/gems/dependency_api_spec.rb
+++ b/spec/bundler/install/gems/dependency_api_spec.rb
@@ -7,12 +7,12 @@ RSpec.describe "gemcutter's dependency API" do
it "should use the API" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should URI encode gem names" do
@@ -21,7 +21,7 @@ RSpec.describe "gemcutter's dependency API" do
gem " sinatra"
G
- bundle :install, artifice: "endpoint", raise_on_error: false
+ bundle :install, :artifice => "endpoint", :raise_on_error => false
expect(err).to include("' sinatra' is not a valid gem name because it contains whitespace.")
end
@@ -31,7 +31,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rails"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}/...")
expect(the_bundle).to include_gems(
"rails 2.3.2",
@@ -49,22 +49,22 @@ RSpec.describe "gemcutter's dependency API" do
gem "net-sftp"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(the_bundle).to include_gems "net-sftp 1.1.1"
end
it "should use the endpoint when using deployment mode" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "handles git dependencies that are in rubygems" do
@@ -75,12 +75,12 @@ RSpec.describe "gemcutter's dependency API" do
gemfile <<-G
source "#{source_uri}"
- git "#{lib_path("foo-1.0")}" do
+ git "#{file_uri_for(lib_path("foo-1.0"))}" do
gem 'foo'
end
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -93,13 +93,13 @@ RSpec.describe "gemcutter's dependency API" do
gemfile <<-G
source "#{source_uri}"
- gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -108,35 +108,35 @@ RSpec.describe "gemcutter's dependency API" do
build_git "foo"
gemfile <<-G
source "#{source_uri}"
- gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle "install", artifice: "endpoint"
+ bundle "install", :artifice => "endpoint"
bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(the_bundle).to include_gems("foo 1.0")
end
it "falls back when the API errors out" do
- simulate_platform x86_mswin32 do
- build_repo2 do
- # The rcov gem is platform mswin32, but has no arch
- build_gem "rcov" do |s|
- s.platform = Gem::Platform.new([nil, "mswin32", nil])
- s.write "lib/rcov.rb", "RCOV = '1.0.0'"
- end
+ simulate_platform x86_mswin32
+
+ build_repo2 do
+ # The rcov gem is platform mswin32, but has no arch
+ build_gem "rcov" do |s|
+ s.platform = Gem::Platform.new([nil, "mswin32", nil])
+ s.write "lib/rcov.rb", "RCOV = '1.0.0'"
end
+ end
- gemfile <<-G
- source "#{source_uri}"
- gem "rcov"
- G
+ gemfile <<-G
+ source "#{source_uri}"
+ gem "rcov"
+ G
- bundle :install, artifice: "windows", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
- expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "rcov 1.0.0"
- end
+ bundle :install, :artifice => "windows", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ expect(out).to include("Fetching source index from #{source_uri}")
+ expect(the_bundle).to include_gems "rcov 1.0.0"
end
it "falls back when hitting the Gemcutter Dependency Limit" do
@@ -147,10 +147,10 @@ RSpec.describe "gemcutter's dependency API" do
gem "actionmailer"
gem "activeresource"
gem "thin"
- gem "myrack"
+ gem "rack"
gem "rails"
G
- bundle :install, artifice: "endpoint_fallback"
+ bundle :install, :artifice => "endpoint_fallback"
expect(out).to include("Fetching source index from #{source_uri}")
expect(the_bundle).to include_gems(
@@ -160,7 +160,7 @@ RSpec.describe "gemcutter's dependency API" do
"activeresource 2.3.2",
"activesupport 2.3.2",
"thin 1.0.0",
- "myrack 1.0.0",
+ "rack 1.0.0",
"rails 2.3.2"
)
end
@@ -168,39 +168,39 @@ RSpec.describe "gemcutter's dependency API" do
it "falls back when Gemcutter API doesn't return proper Marshal format" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "endpoint_marshal_fail"
+ bundle :install, :verbose => true, :artifice => "endpoint_marshal_fail"
expect(out).to include("could not fetch from the dependency API, trying the full index")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "falls back when the API URL returns 403 Forbidden" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "endpoint_api_forbidden"
+ bundle :install, :verbose => true, :artifice => "endpoint_api_forbidden"
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "handles host redirects" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_host_redirect"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "endpoint_host_redirect"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "handles host redirects without Gem::Net::HTTP::Persistent" do
+ it "handles host redirects without Net::HTTP::Persistent" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
FileUtils.mkdir_p lib_path
@@ -216,18 +216,18 @@ RSpec.describe "gemcutter's dependency API" do
H
end
- bundle :install, artifice: "endpoint_host_redirect", requires: [lib_path("disable_net_http_persistent.rb")]
+ bundle :install, :artifice => "endpoint_host_redirect", :requires => [lib_path("disable_net_http_persistent.rb")]
expect(out).to_not match(/Too many redirects/)
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "timeouts when Bundler::Fetcher redirects too much" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_redirect", raise_on_error: false
+ bundle :install, :artifice => "endpoint_redirect", :raise_on_error => false
expect(err).to match(/Too many redirects/)
end
@@ -235,27 +235,27 @@ RSpec.describe "gemcutter's dependency API" do
it "should use the modern index for install" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --full-index", artifice: "endpoint"
+ bundle "install --full-index", :artifice => "endpoint"
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should use the modern index for update" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "update --full-index", artifice: "endpoint", all: true
+ bundle "update --full-index", :artifice => "endpoint", :all => true
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
- it "fetches again when more dependencies are found in subsequent sources", bundler: "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -269,7 +269,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "back_deps"
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
end
@@ -288,33 +288,33 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
end
it "fetches gem versions even when those gems are already installed" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
- bundle :install, artifice: "endpoint_extra_api"
+ bundle :install, :artifice => "endpoint_extra_api"
build_repo4 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
gemfile <<-G
source "#{source_uri}" do; end
source "#{source_uri}/extra"
- gem "myrack", "1.2"
+ gem "rack", "1.2"
G
- bundle :install, artifice: "endpoint_extra_api"
- expect(the_bundle).to include_gems "myrack 1.2"
+ bundle :install, :artifice => "endpoint_extra_api"
+ expect(the_bundle).to include_gems "rack 1.2"
end
- it "considers all possible versions of dependencies from all api gem sources", bundler: "< 3" do
+ it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 3" do
# In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that
# exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0
# of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other
@@ -332,7 +332,7 @@ RSpec.describe "gemcutter's dependency API" do
gem 'somegem', '1.0.0'
G
- bundle :install, artifice: "endpoint_extra_api"
+ bundle :install, :artifice => "endpoint_extra_api"
expect(the_bundle).to include_gems "somegem 1.0.0"
expect(the_bundle).to include_gems "activesupport 1.2.3"
@@ -353,13 +353,13 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
expect(out).to include("Fetching gem metadata from http://localgemserver.test/.")
expect(out).to include("Fetching source index from http://localgemserver.test/extra")
end
- it "does not fetch every spec when doing back deps", bundler: "< 3" do
+ it "does not fetch every spec if the index of gems is large when doing back deps", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -369,7 +369,9 @@ RSpec.describe "gemcutter's dependency API" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "endpoint_extra_missing"
+ api_request_limit = low_api_request_limit_for(gem_repo2)
+
+ install_gemfile <<-G, :artifice => "endpoint_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation)
source "#{source_uri}"
source "#{source_uri}/extra"
gem "back_deps"
@@ -378,7 +380,7 @@ RSpec.describe "gemcutter's dependency API" do
expect(the_bundle).to include_gems "back_deps 1.0"
end
- it "does not fetch every spec when doing back deps using blocks" do
+ it "does not fetch every spec if the index of gems is large when doing back deps using blocks" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -388,7 +390,9 @@ RSpec.describe "gemcutter's dependency API" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "endpoint_extra_missing"
+ api_request_limit = low_api_request_limit_for(gem_repo2)
+
+ install_gemfile <<-G, :artifice => "endpoint_extra_missing", :requires => [api_request_limit_hack_file], :env => { "BUNDLER_SPEC_API_REQUEST_LIMIT" => api_request_limit.to_s }.merge(env_for_missing_prerelease_default_gem_activation)
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -398,7 +402,7 @@ RSpec.describe "gemcutter's dependency API" do
expect(the_bundle).to include_gems "back_deps 1.0"
end
- it "fetches again when more dependencies are found in subsequent sources using deployment mode", bundler: "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources using deployment mode", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -412,9 +416,9 @@ RSpec.describe "gemcutter's dependency API" do
gem "back_deps"
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -433,9 +437,9 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
bundle "config set --local deployment true"
- bundle "install", artifice: "endpoint_extra"
+ bundle "install", :artifice => "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -445,7 +449,7 @@ RSpec.describe "gemcutter's dependency API" do
build_gem "foo", "2.0"
end
- install_gemfile <<-G, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, verbose: true
+ install_gemfile <<-G, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :verbose => true
source "#{source_uri}"
gem "foo"
@@ -468,70 +472,70 @@ RSpec.describe "gemcutter's dependency API" do
gem "bundler_dep"
G
- bundle :install, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle :install, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "installs the binstubs", bundler: "< 3" do
+ it "installs the binstubs", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --binstubs", artifice: "endpoint"
+ bundle "install --binstubs", :artifice => "endpoint"
- gembin "myrackup"
+ gembin "rackup"
expect(out).to eq("1.0.0")
end
- it "installs the bins when using --path and uses autoclean", bundler: "< 3" do
+ it "installs the bins when using --path and uses autoclean", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --path vendor/bundle", artifice: "endpoint"
+ bundle "install --path vendor/bundle", :artifice => "endpoint"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
- it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do
+ it "installs the bins when using --path and uses bundle clean", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --path vendor/bundle --no-clean", artifice: "endpoint"
+ bundle "install --path vendor/bundle --no-clean", :artifice => "endpoint"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "prints post_install_messages" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack-obama'
+ gem 'rack-obama'
G
- bundle :install, artifice: "endpoint"
- expect(out).to include("Post-install message from myrack:")
+ bundle :install, :artifice => "endpoint"
+ expect(out).to include("Post-install message from rack:")
end
it "should display the post install message for a dependency" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack_middleware'
+ gem 'rack_middleware'
G
- bundle :install, artifice: "endpoint"
- expect(out).to include("Post-install message from myrack:")
- expect(out).to include("Myrack's post install message")
+ bundle :install, :artifice => "endpoint"
+ expect(out).to include("Post-install message from rack:")
+ expect(out).to include("Rack's post install message")
end
context "when using basic authentication" do
let(:user) { "user" }
let(:password) { "pass" }
let(:basic_auth_source_uri) do
- uri = Gem::URI.parse(source_uri)
+ uri = Bundler::URI.parse(source_uri)
uri.user = user
uri.password = password
@@ -541,82 +545,82 @@ RSpec.describe "gemcutter's dependency API" do
it "passes basic authentication details and strips out creds" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_basic_authentication"
+ bundle :install, :artifice => "endpoint_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "passes basic authentication details and strips out creds also in verbose mode" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "endpoint_basic_authentication"
+ bundle :install, :verbose => true, :artifice => "endpoint_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "strips http basic authentication creds for modern index" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_marshal_fail_basic_authentication"
+ bundle :install, :artifice => "endpoint_marshal_fail_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "strips http basic auth creds when it can't reach the server" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_500", raise_on_error: false
+ bundle :install, :artifice => "endpoint_500", :raise_on_error => false
expect(out).not_to include("#{user}:#{password}")
end
- it "strips http basic auth creds when warning about ambiguous sources", bundler: "< 3" do
+ it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 3" do
gemfile <<-G
source "#{basic_auth_source_uri}"
source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_basic_authentication"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
+ bundle :install, :artifice => "endpoint_basic_authentication"
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not pass the user / password to different hosts on redirect" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_creds_diff_host"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "endpoint_creds_diff_host"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
describe "with host including dashes" do
before do
gemfile <<-G
source "http://local-gemserver.test"
- gem "myrack"
+ gem "rack"
G
end
it "reads authentication details from a valid ENV variable" do
- bundle :install, artifice: "endpoint_strict_basic_authentication", env: { "BUNDLE_LOCAL___GEMSERVER__TEST" => "#{user}:#{password}" }
+ bundle :install, :artifice => "endpoint_strict_basic_authentication", :env => { "BUNDLE_LOCAL___GEMSERVER__TEST" => "#{user}:#{password}" }
expect(out).to include("Fetching gem metadata from http://local-gemserver.test")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -624,57 +628,57 @@ RSpec.describe "gemcutter's dependency API" do
before do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
end
it "reads authentication details by host name from bundle config" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "reads authentication details by full url from bundle config" do
# The trailing slash is necessary here; Fetcher canonicalizes the URI.
bundle "config set #{source_uri}/ #{user}:#{password}"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should use the API" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "prefers auth supplied in the source uri" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
bundle "config set #{source_hostname} otheruser:wrong"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "shows instructions if auth is not provided for the source" do
- bundle :install, artifice: "endpoint_strict_basic_authentication", raise_on_error: false
+ bundle :install, :artifice => "endpoint_strict_basic_authentication", :raise_on_error => false
expect(err).to include("bundle config set --global #{source_hostname} username:password")
end
it "fails if authentication has already been provided, but failed" do
bundle "config set #{source_hostname} #{user}:wrong"
- bundle :install, artifice: "endpoint_strict_basic_authentication", raise_on_error: false
+ bundle :install, :artifice => "endpoint_strict_basic_authentication", :raise_on_error => false
expect(err).to include("Bad username or password")
end
end
@@ -685,11 +689,11 @@ RSpec.describe "gemcutter's dependency API" do
it "passes basic authentication details" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_basic_authentication"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "endpoint_basic_authentication"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
end
@@ -710,10 +714,10 @@ RSpec.describe "gemcutter's dependency API" do
it "explains what to do to get it" do
gemfile <<-G
source "#{source_uri.gsub(/http/, "https")}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "fail", env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false
+ bundle :install, :env => { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, :raise_on_error => false
expect(err).to include("OpenSSL")
end
end
@@ -723,17 +727,17 @@ RSpec.describe "gemcutter's dependency API" do
# Install a monkeypatch that reproduces the effects of openssl raising
# a certificate validation error when RubyGems tries to connect.
gemfile <<-G
- class Gem::Net::HTTP
+ class Net::HTTP
def start
raise OpenSSL::SSL::SSLError, "certificate verify failed"
end
end
source "#{source_uri.gsub(/http/, "https")}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to match(/could not verify the SSL certificate/i)
end
end
@@ -741,16 +745,16 @@ RSpec.describe "gemcutter's dependency API" do
context ".gemrc with sources is present" do
it "uses other sources declared in the Gemfile" do
File.open(home(".gemrc"), "w") do |file|
- file.puts({ sources: ["https://rubygems.org"] }.to_yaml)
+ file.puts({ :sources => ["https://rubygems.org"] }.to_yaml)
end
begin
gemfile <<-G
source "#{source_uri}"
- gem 'myrack'
+ gem 'rack'
G
- bundle "install", artifice: "endpoint_marshal_fail"
+ bundle "install", :artifice => "endpoint_marshal_fail"
ensure
home(".gemrc").rmtree
end
diff --git a/spec/bundler/install/gems/env_spec.rb b/spec/bundler/install/gems/env_spec.rb
index 6d5aa456fe..a6dfadcfc8 100644
--- a/spec/bundler/install/gems/env_spec.rb
+++ b/spec/bundler/install/gems/env_spec.rb
@@ -4,104 +4,104 @@ RSpec.describe "bundle install with ENV conditionals" do
describe "when just setting an ENV key as a string" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env "BUNDLER_TEST" do
- gem "myrack"
+ gem "rack"
end
G
end
it "excludes the gems when the ENV variable is not set" do
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "includes the gems when the ENV variable is set" do
ENV["BUNDLER_TEST"] = "1"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
describe "when just setting an ENV key as a symbol" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env :BUNDLER_TEST do
- gem "myrack"
+ gem "rack"
end
G
end
it "excludes the gems when the ENV variable is not set" do
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "includes the gems when the ENV variable is set" do
ENV["BUNDLER_TEST"] = "1"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
describe "when setting a string to match the env" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env "BUNDLER_TEST" => "foo" do
- gem "myrack"
+ gem "rack"
end
G
end
it "excludes the gems when the ENV variable is not set" do
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "excludes the gems when the ENV variable is set but does not match the condition" do
ENV["BUNDLER_TEST"] = "1"
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "includes the gems when the ENV variable is set and matches the condition" do
ENV["BUNDLER_TEST"] = "foo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
describe "when setting a regex to match the env" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env "BUNDLER_TEST" => /foo/ do
- gem "myrack"
+ gem "rack"
end
G
end
it "excludes the gems when the ENV variable is not set" do
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "excludes the gems when the ENV variable is set but does not match the condition" do
ENV["BUNDLER_TEST"] = "fo"
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "includes the gems when the ENV variable is set and matches the condition" do
ENV["BUNDLER_TEST"] = "foobar"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
end
diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb
index b7e1b5f1bd..4bbb2ea038 100644
--- a/spec/bundler/install/gems/flex_spec.rb
+++ b/spec/bundler/install/gems/flex_spec.rb
@@ -3,30 +3,30 @@
RSpec.describe "bundle flex_install" do
it "installs the gems as expected" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).to be_locked
end
it "installs even when the lockfile is invalid" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).to be_locked
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', '1.0'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', '1.0'
G
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).to be_locked
end
@@ -34,19 +34,19 @@ RSpec.describe "bundle flex_install" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama"
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "myrack-obama 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "rack-obama 1.0.0"
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama", "1.0"
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "myrack-obama 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "rack-obama 1.0.0"
end
describe "adding new gems" do
@@ -54,38 +54,38 @@ RSpec.describe "bundle flex_install" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
G
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
gem 'activesupport', '2.3.5'
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5"
end
it "keeps child dependencies pinned" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama"
G
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama"
gem "thin"
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "myrack-obama 1.0", "thin 1.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "rack-obama 1.0", "thin 1.0"
end
end
@@ -93,43 +93,43 @@ RSpec.describe "bundle flex_install" do
it "removes gems without changing the versions of remaining gems" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
gem 'activesupport', '2.3.5'
G
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
gem 'activesupport', '2.3.2'
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.2"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.2"
end
it "removes top level dependencies when removed from the Gemfile while leaving other dependencies intact" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
gem 'activesupport', '2.3.5'
G
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
G
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
@@ -138,21 +138,21 @@ RSpec.describe "bundle flex_install" do
it "removes child dependencies" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack-obama'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack-obama'
gem 'activesupport'
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "myrack-obama 1.0.0", "activesupport 2.3.5"
+ expect(the_bundle).to include_gems "rack 1.0.0", "rack-obama 1.0.0", "activesupport 2.3.5"
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'activesupport'
G
expect(the_bundle).to include_gems "activesupport 2.3.5"
- expect(the_bundle).not_to include_gems "myrack-obama", "myrack"
+ expect(the_bundle).not_to include_gems "rack-obama", "rack"
end
end
@@ -160,63 +160,63 @@ RSpec.describe "bundle flex_install" do
before(:each) do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack_middleware"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack_middleware"
G
- expect(the_bundle).to include_gems "myrack_middleware 1.0", "myrack 0.9.1"
+ expect(the_bundle).to include_gems "rack_middleware 1.0", "rack 0.9.1"
build_repo2 do
- build_gem "myrack-obama", "2.0" do |s|
- s.add_dependency "myrack", "=1.2"
+ build_gem "rack-obama", "2.0" do |s|
+ s.add_dependency "rack", "=1.2"
end
- build_gem "myrack_middleware", "2.0" do |s|
- s.add_dependency "myrack", ">=1.0"
+ build_gem "rack_middleware", "2.0" do |s|
+ s.add_dependency "rack", ">=1.0"
end
end
gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama", "2.0"
- gem "myrack_middleware"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama", "2.0"
+ gem "rack_middleware"
G
end
it "does not install gems whose dependencies are not met" do
- bundle :install, raise_on_error: false
- ruby <<-RUBY, raise_on_error: false
+ bundle :install, :raise_on_error => false
+ ruby <<-RUBY, :raise_on_error => false
require 'bundler/setup'
RUBY
- expect(err).to match(/could not find gem 'myrack-obama/i)
+ expect(err).to match(/could not find gem 'rack-obama/i)
end
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 myrack-obama >= 2.0 depends on myrack = 1.2
- and myrack = 1.2 could not be found in rubygems repository https://gem.repo2/ or installed locally,
- myrack-obama >= 2.0 cannot be used.
- So, because Gemfile depends on myrack-obama = 2.0,
+ Because rack-obama >= 2.0 depends on rack = 1.2
+ and rack = 1.2 could not be found in rubygems repository #{file_uri_for(gem_repo2)}/ or installed locally,
+ rack-obama >= 2.0 is forbidden.
+ So, because Gemfile depends on rack-obama = 2.0,
version solving has failed.
E
- bundle :install, retry: 0, raise_on_error: false
+ bundle :install, :retry => 0, :raise_on_error => false
expect(err).to end_with(nice_error)
end
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
- Bundler could not find compatible versions for gem "myrack-obama":
+ bad_error = <<-E.strip.gsub(/^ {8}/, "")
+ Bundler could not find compatible versions for gem "rack-obama":
In Gemfile:
- myrack-obama (= 2.0)
+ rack-obama (= 2.0)
E
- bundle "update myrack_middleware", retry: 0, raise_on_error: false
+ bundle "update rack_middleware", :retry => 0, :raise_on_error => false
expect(err).not_to end_with(bad_error)
end
end
@@ -233,19 +233,19 @@ RSpec.describe "bundle flex_install" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "jekyll-feed", "~> 0.12"
G
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "github-pages", "~> 226"
gem "jekyll-feed", "~> 0.12"
G
end
it "discards the conflicting lockfile information and resolves properly" do
- bundle :update, raise_on_error: false, all: true
+ bundle :update, :raise_on_error => false, :all => true
expect(err).to be_empty
end
end
@@ -253,48 +253,43 @@ RSpec.describe "bundle flex_install" do
describe "subtler cases" do
before :each do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
+ gem "rack-obama"
G
end
it "should work when you install" do
bundle "install"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "myrack", "0.9.1"
- c.checksum gem_repo1, "myrack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
- myrack-obama (1.0)
- myrack
+ rack (0.9.1)
+ rack-obama (1.0)
+ rack
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack (= 0.9.1)
- myrack-obama
- #{checksums}
+ rack (= 0.9.1)
+ rack-obama
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "should work when you update" do
- bundle "update myrack"
+ bundle "update rack"
end
end
@@ -302,37 +297,33 @@ RSpec.describe "bundle flex_install" do
it "updates the lockfile" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
- source "https://gem.repo2" do
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo2)}" do
end
- gem "myrack"
+ gem "rack"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "myrack", "1.0.0"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -344,17 +335,17 @@ RSpec.describe "bundle flex_install" do
before(:each) do
build_repo2 do
build_gem "capybara", "0.3.9" do |s|
- s.add_dependency "myrack", ">= 1.0.0"
+ s.add_dependency "rack", ">= 1.0.0"
end
- build_gem "myrack", "1.1.0"
+ build_gem "rack", "1.1.0"
build_gem "rails", "3.0.0.rc4" do |s|
- s.add_dependency "myrack", "~> 1.1.0"
+ s.add_dependency "rack", "~> 1.1.0"
end
- build_gem "myrack", "1.2.1"
+ build_gem "rack", "1.2.1"
build_gem "rails", "3.0.0" do |s|
- s.add_dependency "myrack", "~> 1.2.1"
+ s.add_dependency "rack", "~> 1.2.1"
end
end
end
@@ -362,14 +353,14 @@ RSpec.describe "bundle flex_install" do
it "resolves them" do
# install Rails 3.0.0.rc
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0.0.rc4"
gem "capybara", "0.3.9"
G
# upgrade Rails to 3.0.0 and then install again
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0.0"
gem "capybara", "0.3.9"
G
diff --git a/spec/bundler/install/gems/fund_spec.rb b/spec/bundler/install/gems/fund_spec.rb
index 0855a62b86..9aadc9ed25 100644
--- a/spec/bundler/install/gems/fund_spec.rb
+++ b/spec/bundler/install/gems/fund_spec.rb
@@ -32,10 +32,10 @@ RSpec.describe "bundle install" do
context "when gems include a fund URI" do
it "displays the plural fund message after installing" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata'
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
expect(out).to include("2 installed gems you directly depend on are looking for funding.")
@@ -43,9 +43,9 @@ RSpec.describe "bundle install" do
it "displays the singular fund message after installing" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
expect(out).to include("1 installed gem you directly depend on is looking for funding.")
@@ -59,10 +59,10 @@ RSpec.describe "bundle install" do
it "does not display the plural fund message after installing" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata'
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
expect(out).not_to include("2 installed gems you directly depend on are looking for funding.")
@@ -70,9 +70,9 @@ RSpec.describe "bundle install" do
it "does not display the singular fund message after installing" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
expect(out).not_to include("1 installed gem you directly depend on is looking for funding.")
@@ -82,7 +82,7 @@ RSpec.describe "bundle install" do
context "when gems do not include fund messages" do
it "does not display any fund messages" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
@@ -93,7 +93,7 @@ RSpec.describe "bundle install" do
context "when a dependency includes a fund message" do
it "does not display the fund message" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'gem_with_dependent_funding'
G
@@ -111,7 +111,7 @@ RSpec.describe "bundle install" do
}
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'also_has_funding', :git => '#{lib_path("also_has_funding-1.0")}'
G
@@ -125,7 +125,7 @@ RSpec.describe "bundle install" do
}
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'also_has_funding', :git => '#{lib_path("also_has_funding-1.0")}'
G
@@ -135,7 +135,7 @@ RSpec.describe "bundle install" do
}
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'also_has_funding', :git => '#{lib_path("also_has_funding-1.1")}'
G
@@ -149,7 +149,7 @@ RSpec.describe "bundle install" do
}
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'also_has_funding', :git => '#{lib_path("also_has_funding-1.0")}'
G
diff --git a/spec/bundler/install/gems/mirror_spec.rb b/spec/bundler/install/gems/mirror_spec.rb
index 70c0da50ef..9611973701 100644
--- a/spec/bundler/install/gems/mirror_spec.rb
+++ b/spec/bundler/install/gems/mirror_spec.rb
@@ -4,17 +4,17 @@ RSpec.describe "bundle install with a mirror configured" do
describe "when the mirror does not match the gem source" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle "config set --local mirror.http://gems.example.org http://gem-mirror.example.org"
end
it "installs from the normal location" do
bundle :install
- expect(out).to include("Fetching gem metadata from https://gem.repo1")
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(out).to include("Fetching source index from #{file_uri_for(gem_repo1)}")
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
@@ -22,18 +22,18 @@ RSpec.describe "bundle install with a mirror configured" do
before :each do
gemfile <<-G
# This source is bogus and doesn't have the gem we're looking for
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
G
- bundle "config set --local mirror.https://gem.repo2 https://gem.repo1"
+ bundle "config set --local mirror.#{file_uri_for(gem_repo2)} #{file_uri_for(gem_repo1)}"
end
it "installs the gem from the mirror" do
- bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
- expect(out).to include("Fetching gem metadata from https://gem.repo1")
- expect(out).not_to include("Fetching gem metadata from https://gem.repo2")
- expect(the_bundle).to include_gems "myrack 1.0"
+ bundle :install
+ expect(out).to include("Fetching source index from #{file_uri_for(gem_repo1)}")
+ expect(out).not_to include("Fetching source index from #{file_uri_for(gem_repo2)}")
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
end
diff --git a/spec/bundler/install/gems/native_extensions_spec.rb b/spec/bundler/install/gems/native_extensions_spec.rb
index 874818fa87..5c18d2cc51 100644
--- a/spec/bundler/install/gems/native_extensions_spec.rb
+++ b/spec/bundler/install/gems/native_extensions_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe "installing a gem with native extensions" do
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-E
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
name = "c_extension_bundle"
dir_config(name)
raise "OMG" unless with_config("c_extension") == "hello"
@@ -33,7 +34,7 @@ RSpec.describe "installing a gem with native extensions" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "c_extension"
G
@@ -51,6 +52,7 @@ RSpec.describe "installing a gem with native extensions" do
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-E
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
name = "c_extension_bundle"
dir_config(name)
raise "OMG" unless with_config("c_extension") == "hello"
@@ -78,7 +80,7 @@ RSpec.describe "installing a gem with native extensions" do
bundle "config set build.c_extension --with-c_extension=hello"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "c_extension", :git => #{lib_path("c_extension-1.0").to_s.dump}
G
@@ -91,10 +93,11 @@ RSpec.describe "installing a gem with native extensions" do
it "installs correctly from git when multiple gems with extensions share one repository" do
build_repo2 do
["one", "two"].each do |n|
- build_lib "c_extension_#{n}", "1.0", path: lib_path("gems/c_extension_#{n}") do |s|
+ build_lib "c_extension_#{n}", "1.0", :path => lib_path("gems/c_extension_#{n}") do |s|
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-E
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
name = "c_extension_bundle_#{n}"
dir_config(name)
raise "OMG" unless with_config("c_extension_#{n}") == "#{n}"
@@ -119,7 +122,7 @@ RSpec.describe "installing a gem with native extensions" do
C
end
end
- build_git "gems", path: lib_path("gems"), gemspec: false
+ build_git "gems", :path => lib_path("gems"), :gemspec => false
end
bundle "config set build.c_extension_one --with-c_extension_one=one"
@@ -127,13 +130,13 @@ RSpec.describe "installing a gem with native extensions" do
# 1st time, require only one gem -- only one of the extensions gets built.
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "c_extension_one", :git => #{lib_path("gems").to_s.dump}
G
# 2nd time, require both gems -- we need both extensions to be built now.
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "c_extension_one", :git => #{lib_path("gems").to_s.dump}
gem "c_extension_two", :git => #{lib_path("gems").to_s.dump}
G
@@ -147,6 +150,7 @@ RSpec.describe "installing a gem with native extensions" do
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-E
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
name = "c_extension_bundle"
dir_config(name)
raise "OMG" unless with_config("c_extension") == "hello" && with_config("c_extension_bundle-dir") == "hola"
@@ -174,7 +178,7 @@ RSpec.describe "installing a gem with native extensions" do
bundle "config set build.c_extension --with-c_extension=hello --with-c_extension_bundle-dir=hola"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "c_extension", :git => #{lib_path("c_extension-1.0").to_s.dump}
G
diff --git a/spec/bundler/install/gems/post_install_spec.rb b/spec/bundler/install/gems/post_install_spec.rb
index af753dba3e..7426f54877 100644
--- a/spec/bundler/install/gems/post_install_spec.rb
+++ b/spec/bundler/install/gems/post_install_spec.rb
@@ -5,26 +5,26 @@ RSpec.describe "bundle install" do
context "when gems include post install messages" do
it "should display the post-install messages after installing" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gem 'thin'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
bundle :install
- expect(out).to include("Post-install message from myrack:")
- expect(out).to include("Myrack's post install message")
+ expect(out).to include("Post-install message from rack:")
+ expect(out).to include("Rack's post install message")
expect(out).to include("Post-install message from thin:")
expect(out).to include("Thin's post install message")
- expect(out).to include("Post-install message from myrack-obama:")
- expect(out).to include("Myrack-obama's post install message")
+ expect(out).to include("Post-install message from rack-obama:")
+ expect(out).to include("Rack-obama's post install message")
end
end
context "when gems do not include post install messages" do
it "should not display any post-install messages" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
G
@@ -36,13 +36,13 @@ RSpec.describe "bundle install" do
context "when a dependency includes a post install message" do
it "should display the post install message" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack_middleware'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack_middleware'
G
bundle :install
- expect(out).to include("Post-install message from myrack:")
- expect(out).to include("Myrack's post install message")
+ expect(out).to include("Post-install message from rack:")
+ expect(out).to include("Rack's post install message")
end
end
end
@@ -54,7 +54,7 @@ RSpec.describe "bundle install" do
s.post_install_message = "Foo's post install message"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.0")}'
G
@@ -68,7 +68,7 @@ RSpec.describe "bundle install" do
s.post_install_message = "Foo's post install message"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.0")}'
G
bundle :install
@@ -77,7 +77,7 @@ RSpec.describe "bundle install" do
s.post_install_message = "Foo's 1.1 post install message"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.1")}'
G
bundle :install
@@ -91,7 +91,7 @@ RSpec.describe "bundle install" do
s.post_install_message = "Foo's post install message"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.0")}'
G
@@ -110,7 +110,7 @@ RSpec.describe "bundle install" do
s.post_install_message = nil
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.0")}'
G
@@ -123,11 +123,11 @@ RSpec.describe "bundle install" do
context "when ignore post-install messages for gem is set" do
it "doesn't display any post-install messages" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "config set ignore_messages.myrack true"
+ bundle "config set ignore_messages.rack true"
bundle :install
expect(out).not_to include("Post-install message")
@@ -137,8 +137,8 @@ RSpec.describe "bundle install" do
context "when ignore post-install messages for all gems" do
it "doesn't display any post-install messages" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set ignore_messages true"
diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb
index 694bc7c131..279d3422c1 100644
--- a/spec/bundler/install/gems/resolving_spec.rb
+++ b/spec/bundler/install/gems/resolving_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe "bundle install with install-time dependencies" do
it "installs gems with implicit rake dependencies" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "with_implicit_rake_dep"
gem "another_implicit_rake_dep"
gem "rake"
@@ -84,7 +84,7 @@ RSpec.describe "bundle install with install-time dependencies" do
it "installs gems with implicit rake dependencies without rake previously installed" do
with_path_as("") do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "with_implicit_rake_dep"
gem "another_implicit_rake_dep"
gem "rake"
@@ -100,32 +100,30 @@ RSpec.describe "bundle install with install-time dependencies" do
expect(out).to eq("YES\nYES")
end
- it "does not install gems with a dependency with no type" do
+ it "installs gems with a dependency with no type" do
build_repo2
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))
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
gem "actionpack", "2.3.2"
G
- expect(err).to include("Downloading actionpack-2.3.2 revealed dependencies not in the API or the lockfile (activesupport (= 2.3.2)).")
-
- expect(the_bundle).not_to include_gems "actionpack 2.3.2", "activesupport 2.3.2"
+ expect(the_bundle).to include_gems "actionpack 2.3.2", "activesupport 2.3.2"
end
describe "with crazy rubygem plugin stuff" do
it "installs plugins" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "net_b"
G
@@ -133,8 +131,8 @@ RSpec.describe "bundle install with install-time dependencies" do
end
it "installs plugins depended on by other plugins" do
- install_gemfile <<-G, env: { "DEBUG" => "1" }
- source "https://gem.repo2"
+ install_gemfile <<-G, :env => { "DEBUG" => "1" }
+ source "#{file_uri_for(gem_repo2)}"
gem "net_a"
G
@@ -142,8 +140,8 @@ RSpec.describe "bundle install with install-time dependencies" do
end
it "installs multiple levels of dependencies" do
- install_gemfile <<-G, env: { "DEBUG" => "1" }
- source "https://gem.repo2"
+ install_gemfile <<-G, :env => { "DEBUG" => "1" }
+ source "#{file_uri_for(gem_repo2)}"
gem "net_c"
gem "net_e"
G
@@ -154,12 +152,12 @@ RSpec.describe "bundle install with install-time dependencies" do
context "with ENV['BUNDLER_DEBUG_RESOLVER'] set" do
it "produces debug output" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "net_c"
gem "net_e"
G
- bundle :install, env: { "BUNDLER_DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
+ bundle :install, :env => { "BUNDLER_DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
expect(out).to include("Resolving dependencies...")
end
@@ -168,12 +166,12 @@ RSpec.describe "bundle install with install-time dependencies" do
context "with ENV['DEBUG_RESOLVER'] set" do
it "produces debug output" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "net_c"
gem "net_e"
G
- bundle :install, env: { "DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
+ bundle :install, :env => { "DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
expect(out).to include("Resolving dependencies...")
end
@@ -182,17 +180,17 @@ RSpec.describe "bundle install with install-time dependencies" do
context "with ENV['DEBUG_RESOLVER_TREE'] set" do
it "produces debug output" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "net_c"
gem "net_e"
G
- bundle :install, env: { "DEBUG_RESOLVER_TREE" => "1", "DEBUG" => "1" }
+ bundle :install, :env => { "DEBUG_RESOLVER_TREE" => "1", "DEBUG" => "1" }
expect(out).to include(" net_b").
and include("Resolving dependencies...").
and include("Solution found after 1 attempts:").
- and include("selected net_b 1.0")
+ and include("selecting net_b 1.0")
end
end
end
@@ -201,44 +199,44 @@ RSpec.describe "bundle install with install-time dependencies" do
context "allows only an older version" do
it "installs the older version" do
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
- build_gem "myrack", "9001.0.0" do |s|
+ build_gem "rack", "9001.0.0" do |s|
s.required_ruby_version = "> 9000"
end
end
- install_gemfile <<-G
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
ruby "#{Gem.ruby_version}"
- source "https://gem.repo2"
- gem 'myrack'
+ source "http://localgemserver.test/"
+ gem 'rack'
G
- expect(err).to_not include("myrack-9001.0.0 requires ruby version > 9000")
- expect(the_bundle).to include_gems("myrack 1.2")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(the_bundle).to include_gems("rack 1.2")
end
it "installs the older version when using servers not implementing the compact index API" do
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
- build_gem "myrack", "9001.0.0" do |s|
+ build_gem "rack", "9001.0.0" do |s|
s.required_ruby_version = "> 9000"
end
end
- install_gemfile <<-G, artifice: "endpoint"
+ install_gemfile <<-G, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
ruby "#{Gem.ruby_version}"
- source "https://gem.repo2"
- gem 'myrack'
+ source "http://localgemserver.test/"
+ gem 'rack'
G
- expect(err).to_not include("myrack-9001.0.0 requires ruby version > 9000")
- expect(the_bundle).to include_gems("myrack 1.2")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(the_bundle).to include_gems("rack 1.2")
end
context "when there is a lockfile using the newer incompatible version" do
@@ -254,17 +252,13 @@ RSpec.describe "bundle install with install-time dependencies" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "http://localgemserver.test/"
gem 'parallel_tests'
G
- checksums = checksums_section do |c|
- c.checksum gem_repo2, "parallel_tests", "3.8.0"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo2/
+ remote: http://localgemserver.test/
specs:
parallel_tests (3.8.0)
@@ -273,22 +267,18 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
parallel_tests
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "automatically updates lockfile to use the older version" do
- bundle "install --verbose"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "parallel_tests", "3.7.0"
- end
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo2/
+ remote: http://localgemserver.test/
specs:
parallel_tests (3.7.0)
@@ -297,7 +287,7 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
parallel_tests
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -305,7 +295,7 @@ RSpec.describe "bundle install with install-time dependencies" do
it "gives a meaningful error if we're in frozen mode" do
expect do
- bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s, "BUNDLE_FROZEN" => "true" }, :raise_on_error => false
end.not_to change { lockfile }
expect(err).to include("parallel_tests-3.8.0 requires ruby version >= #{next_ruby_minor}")
@@ -338,18 +328,13 @@ RSpec.describe "bundle install with install-time dependencies" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "http://localgemserver.test/"
gem 'rubocop'
G
- checksums = checksums_section do |c|
- c.checksum gem_repo2, "rubocop", "1.35.0"
- c.checksum gem_repo2, "rubocop-ast", "1.21.0"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo2/
+ remote: http://localgemserver.test/
specs:
rubocop (1.35.0)
rubocop-ast (>= 1.20.1, < 2.0)
@@ -360,23 +345,18 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
parallel_tests
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "automatically updates lockfile to use the older compatible versions" do
- bundle "install --verbose"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "rubocop", "1.28.2"
- c.checksum gem_repo2, "rubocop-ast", "1.17.0"
- end
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo2/
+ remote: http://localgemserver.test/
specs:
rubocop (1.28.2)
rubocop-ast (>= 1.17.0, < 2.0)
@@ -387,7 +367,7 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
rubocop
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -407,13 +387,13 @@ RSpec.describe "bundle install with install-time dependencies" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'sorbet', '= 0.5.10554'
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10554)
sorbet-static (= 0.5.10554)
@@ -432,11 +412,11 @@ RSpec.describe "bundle install with install-time dependencies" do
it "raises a proper error" do
simulate_platform "aarch64-linux" do
- bundle "install", raise_on_error: false
+ 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 https://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
@@ -445,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: https://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 "https://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 https://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|
@@ -508,14 +432,14 @@ RSpec.describe "bundle install with install-time dependencies" do
end
end
- build_lib("foo", path: bundled_app) do |s|
+ build_lib("foo", :path => bundled_app) do |s|
s.required_ruby_version = ">= #{Gem.ruby_version}"
s.add_dependency "requires-old-ruby"
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo4"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo4)}"
gemspec
G
@@ -533,47 +457,47 @@ RSpec.describe "bundle install with install-time dependencies" do
it "installs the older version under rate limiting conditions" do
build_repo4 do
- build_gem "myrack", "9001.0.0" do |s|
+ build_gem "rack", "9001.0.0" do |s|
s.required_ruby_version = "> 9000"
end
- build_gem "myrack", "1.2"
+ build_gem "rack", "1.2"
build_gem "foo1", "1.0"
end
- install_gemfile <<-G, artifice: "compact_index_rate_limited"
+ install_gemfile <<-G, :artifice => "compact_index_rate_limited", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
ruby "#{Gem.ruby_version}"
- source "https://gem.repo4"
- gem 'myrack'
+ source "http://localgemserver.test/"
+ gem 'rack'
gem 'foo1'
G
- expect(err).to_not include("myrack-9001.0.0 requires ruby version > 9000")
- expect(the_bundle).to include_gems("myrack 1.2")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(the_bundle).to include_gems("rack 1.2")
end
it "installs the older not platform specific version" do
build_repo4 do
- build_gem "myrack", "9001.0.0" do |s|
+ build_gem "rack", "9001.0.0" do |s|
s.required_ruby_version = "> 9000"
end
- build_gem "myrack", "1.2" do |s|
+ build_gem "rack", "1.2" do |s|
s.platform = x86_mingw32
s.required_ruby_version = "> 9000"
end
- build_gem "myrack", "1.2"
+ build_gem "rack", "1.2"
end
simulate_platform x86_mingw32 do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
ruby "#{Gem.ruby_version}"
- source "https://gem.repo4"
- gem 'myrack'
+ source "http://localgemserver.test/"
+ gem 'rack'
G
end
- expect(err).to_not include("myrack-9001.0.0 requires ruby version > 9000")
- expect(err).to_not include("myrack-1.2-#{Bundler.local_platform} requires ruby version > 9000")
- expect(the_bundle).to include_gems("myrack 1.2")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(err).to_not include("rack-1.2-#{Bundler.local_platform} requires ruby version > 9000")
+ expect(the_bundle).to include_gems("rack 1.2")
end
end
@@ -590,14 +514,14 @@ RSpec.describe "bundle install with install-time dependencies" do
let(:error_message_requirement) { "= #{Gem.ruby_version}" }
it "raises a proper error that mentions the current Ruby version during resolution" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :raise_on_error => false
+ source "http://localgemserver.test/"
gem 'require_ruby'
G
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
@@ -611,15 +535,15 @@ RSpec.describe "bundle install with install-time dependencies" do
shared_examples_for "ruby version conflicts" do
it "raises an error during resolution" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :raise_on_error => false
+ source "http://localgemserver.test/"
ruby #{ruby_requirement}
gem 'require_ruby'
G
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
@@ -657,13 +581,13 @@ RSpec.describe "bundle install with install-time dependencies" do
end
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem 'require_rubygems'
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.
@@ -673,55 +597,4 @@ RSpec.describe "bundle install with install-time dependencies" do
expect(err).to end_with(nice_error)
end
end
-
- context "when non platform specific gems bring more dependencies", :truffleruby_only do
- before do
- build_repo4 do
- build_gem "foo", "1.0" do |s|
- s.add_dependency "bar"
- end
-
- build_gem "foo", "2.0" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "bar"
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem "foo"
- G
- end
-
- it "locks both ruby and current platform, and resolve to ruby variants that install on truffleruby" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "bar", "1.0"
- end
-
- simulate_platform "x86_64-linux" do
- bundle "install"
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- bar (1.0)
- foo (1.0)
- bar
-
- PLATFORMS
- ruby
- x86_64-linux
-
- DEPENDENCIES
- foo
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
- end
end
diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb